Completed
Pull Request — master (#3813)
by Maxence
12:19
created
apps/dav/lib/CardDAV/AddressBookRoot.php 2 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -30,7 +30,7 @@
 block discarded – undo
30 30
 
31 31
 	/**
32 32
 	 * @param \Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend
33
-	 * @param \Sabre\CardDAV\Backend\BackendInterface $carddavBackend
33
+	 * @param CardDavBackend $carddavBackend
34 34
 	 * @param string $principalPrefix
35 35
 	 */
36 36
 	public function __construct(\Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend, \Sabre\CardDAV\Backend\BackendInterface $carddavBackend, $principalPrefix = 'principals') {
Please login to merge, or discard this patch.
Indentation   +33 added lines, -33 removed lines patch added patch discarded remove patch
@@ -25,46 +25,46 @@
 block discarded – undo
25 25
 
26 26
 class AddressBookRoot extends \Sabre\CardDAV\AddressBookRoot {
27 27
 
28
-	/** @var IL10N */
29
-	protected $l10n;
28
+    /** @var IL10N */
29
+    protected $l10n;
30 30
 
31
-	/**
32
-	 * @param \Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend
33
-	 * @param \Sabre\CardDAV\Backend\BackendInterface $carddavBackend
34
-	 * @param string $principalPrefix
35
-	 */
36
-	public function __construct(\Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend, \Sabre\CardDAV\Backend\BackendInterface $carddavBackend, $principalPrefix = 'principals') {
37
-		parent::__construct($principalBackend, $carddavBackend, $principalPrefix);
38
-		$this->l10n = \OC::$server->getL10N('dav');
39
-	}
31
+    /**
32
+     * @param \Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend
33
+     * @param \Sabre\CardDAV\Backend\BackendInterface $carddavBackend
34
+     * @param string $principalPrefix
35
+     */
36
+    public function __construct(\Sabre\DAVACL\PrincipalBackend\BackendInterface $principalBackend, \Sabre\CardDAV\Backend\BackendInterface $carddavBackend, $principalPrefix = 'principals') {
37
+        parent::__construct($principalBackend, $carddavBackend, $principalPrefix);
38
+        $this->l10n = \OC::$server->getL10N('dav');
39
+    }
40 40
 
41
-	/**
42
-	 * This method returns a node for a principal.
43
-	 *
44
-	 * The passed array contains principal information, and is guaranteed to
45
-	 * at least contain a uri item. Other properties may or may not be
46
-	 * supplied by the authentication backend.
47
-	 *
48
-	 * @param array $principal
49
-	 * @return \Sabre\DAV\INode
50
-	 */
51
-	function getChildForPrincipal(array $principal) {
41
+    /**
42
+     * This method returns a node for a principal.
43
+     *
44
+     * The passed array contains principal information, and is guaranteed to
45
+     * at least contain a uri item. Other properties may or may not be
46
+     * supplied by the authentication backend.
47
+     *
48
+     * @param array $principal
49
+     * @return \Sabre\DAV\INode
50
+     */
51
+    function getChildForPrincipal(array $principal) {
52 52
 
53
-		return new UserAddressBooks($this->carddavBackend, $principal['uri'], $this->l10n);
53
+        return new UserAddressBooks($this->carddavBackend, $principal['uri'], $this->l10n);
54 54
 
55
-	}
55
+    }
56 56
 
57
-	function getName() {
57
+    function getName() {
58 58
 
59
-		if ($this->principalPrefix === 'principals') {
60
-			return parent::getName();
61
-		}
62
-		// Grabbing all the components of the principal path.
63
-		$parts = explode('/', $this->principalPrefix);
59
+        if ($this->principalPrefix === 'principals') {
60
+            return parent::getName();
61
+        }
62
+        // Grabbing all the components of the principal path.
63
+        $parts = explode('/', $this->principalPrefix);
64 64
 
65
-		// We are only interested in the second part.
66
-		return $parts[1];
65
+        // We are only interested in the second part.
66
+        return $parts[1];
67 67
 
68
-	}
68
+    }
69 69
 
70 70
 }
Please login to merge, or discard this patch.
lib/private/Share20/DefaultShareProvider.php 4 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -770,7 +770,7 @@
 block discarded – undo
770 770
 
771 771
 	/**
772 772
 	 * @param Share[] $shares
773
-	 * @param $userId
773
+	 * @param string $userId
774 774
 	 * @return Share[] The updates shares if no update is found for a share return the original
775 775
 	 */
776 776
 	private function resolveGroupShares($shares, $userId) {
Please login to merge, or discard this patch.
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -24,7 +24,6 @@
 block discarded – undo
24 24
 namespace OC\Share20;
25 25
 
26 26
 use OC\Files\Cache\Cache;
27
-use OC\Files\Cache\CacheEntry;
28 27
 use OCP\Files\File;
29 28
 use OCP\Files\Folder;
30 29
 use OCP\Share\IShareProvider;
Please login to merge, or discard this patch.
Spacing   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -285,7 +285,7 @@  discard block
 block discarded – undo
285 285
 			->orderBy('id');
286 286
 
287 287
 		$cursor = $qb->execute();
288
-		while($data = $cursor->fetch()) {
288
+		while ($data = $cursor->fetch()) {
289 289
 			$children[] = $this->createShare($data);
290 290
 		}
291 291
 		$cursor->closeCursor();
@@ -486,7 +486,7 @@  discard block
 block discarded – undo
486 486
 			);
487 487
 		}
488 488
 
489
-		$qb->innerJoin('s', 'filecache' ,'f', 's.file_source = f.fileid');
489
+		$qb->innerJoin('s', 'filecache', 'f', 's.file_source = f.fileid');
490 490
 		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
491 491
 
492 492
 		$qb->orderBy('id');
@@ -542,7 +542,7 @@  discard block
 block discarded – undo
542 542
 
543 543
 		$cursor = $qb->execute();
544 544
 		$shares = [];
545
-		while($data = $cursor->fetch()) {
545
+		while ($data = $cursor->fetch()) {
546 546
 			$shares[] = $this->createShare($data);
547 547
 		}
548 548
 		$cursor->closeCursor();
@@ -621,7 +621,7 @@  discard block
 block discarded – undo
621 621
 			->execute();
622 622
 
623 623
 		$shares = [];
624
-		while($data = $cursor->fetch()) {
624
+		while ($data = $cursor->fetch()) {
625 625
 			$shares[] = $this->createShare($data);
626 626
 		}
627 627
 		$cursor->closeCursor();
@@ -691,7 +691,7 @@  discard block
 block discarded – undo
691 691
 
692 692
 			$cursor = $qb->execute();
693 693
 
694
-			while($data = $cursor->fetch()) {
694
+			while ($data = $cursor->fetch()) {
695 695
 				if ($this->isAccessibleResult($data)) {
696 696
 					$shares[] = $this->createShare($data);
697 697
 				}
@@ -706,7 +706,7 @@  discard block
 block discarded – undo
706 706
 			$shares2 = [];
707 707
 
708 708
 			$start = 0;
709
-			while(true) {
709
+			while (true) {
710 710
 				$groups = array_slice($allGroups, $start, 100);
711 711
 				$start += 100;
712 712
 
@@ -749,7 +749,7 @@  discard block
 block discarded – undo
749 749
 					));
750 750
 
751 751
 				$cursor = $qb->execute();
752
-				while($data = $cursor->fetch()) {
752
+				while ($data = $cursor->fetch()) {
753 753
 					if ($offset > 0) {
754 754
 						$offset--;
755 755
 						continue;
@@ -818,14 +818,14 @@  discard block
 block discarded – undo
818 818
 	 */
819 819
 	private function createShare($data) {
820 820
 		$share = new Share($this->rootFolder, $this->userManager);
821
-		$share->setId((int)$data['id'])
822
-			->setShareType((int)$data['share_type'])
823
-			->setPermissions((int)$data['permissions'])
821
+		$share->setId((int) $data['id'])
822
+			->setShareType((int) $data['share_type'])
823
+			->setPermissions((int) $data['permissions'])
824 824
 			->setTarget($data['file_target'])
825
-			->setMailSend((bool)$data['mail_send']);
825
+			->setMailSend((bool) $data['mail_send']);
826 826
 
827 827
 		$shareTime = new \DateTime();
828
-		$shareTime->setTimestamp((int)$data['stime']);
828
+		$shareTime->setTimestamp((int) $data['stime']);
829 829
 		$share->setShareTime($shareTime);
830 830
 
831 831
 		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
@@ -840,7 +840,7 @@  discard block
 block discarded – undo
840 840
 		$share->setSharedBy($data['uid_initiator']);
841 841
 		$share->setShareOwner($data['uid_owner']);
842 842
 
843
-		$share->setNodeId((int)$data['file_source']);
843
+		$share->setNodeId((int) $data['file_source']);
844 844
 		$share->setNodeType($data['item_type']);
845 845
 
846 846
 		if ($data['expiration'] !== null) {
@@ -851,7 +851,7 @@  discard block
 block discarded – undo
851 851
 		if (isset($data['f_permissions'])) {
852 852
 			$entryData = $data;
853 853
 			$entryData['permissions'] = $entryData['f_permissions'];
854
-			$entryData['parent'] = $entryData['f_parent'];;
854
+			$entryData['parent'] = $entryData['f_parent']; ;
855 855
 			$share->setNodeCacheEntry(Cache::cacheEntryFromData($entryData,
856 856
 				\OC::$server->getMimeTypeLoader()));
857 857
 		}
@@ -870,7 +870,7 @@  discard block
 block discarded – undo
870 870
 		$result = [];
871 871
 
872 872
 		$start = 0;
873
-		while(true) {
873
+		while (true) {
874 874
 			/** @var Share[] $shareSlice */
875 875
 			$shareSlice = array_slice($shares, $start, 100);
876 876
 			$start += 100;
@@ -885,7 +885,7 @@  discard block
 block discarded – undo
885 885
 			$shareMap = [];
886 886
 
887 887
 			foreach ($shareSlice as $share) {
888
-				$ids[] = (int)$share->getId();
888
+				$ids[] = (int) $share->getId();
889 889
 				$shareMap[$share->getId()] = $share;
890 890
 			}
891 891
 
@@ -902,8 +902,8 @@  discard block
 block discarded – undo
902 902
 
903 903
 			$stmt = $query->execute();
904 904
 
905
-			while($data = $stmt->fetch()) {
906
-				$shareMap[$data['parent']]->setPermissions((int)$data['permissions']);
905
+			while ($data = $stmt->fetch()) {
906
+				$shareMap[$data['parent']]->setPermissions((int) $data['permissions']);
907 907
 				$shareMap[$data['parent']]->setTarget($data['file_target']);
908 908
 			}
909 909
 
@@ -1000,8 +1000,8 @@  discard block
 block discarded – undo
1000 1000
 
1001 1001
 		$cursor = $qb->execute();
1002 1002
 		$ids = [];
1003
-		while($row = $cursor->fetch()) {
1004
-			$ids[] = (int)$row['id'];
1003
+		while ($row = $cursor->fetch()) {
1004
+			$ids[] = (int) $row['id'];
1005 1005
 		}
1006 1006
 		$cursor->closeCursor();
1007 1007
 
@@ -1043,8 +1043,8 @@  discard block
 block discarded – undo
1043 1043
 
1044 1044
 		$cursor = $qb->execute();
1045 1045
 		$ids = [];
1046
-		while($row = $cursor->fetch()) {
1047
-			$ids[] = (int)$row['id'];
1046
+		while ($row = $cursor->fetch()) {
1047
+			$ids[] = (int) $row['id'];
1048 1048
 		}
1049 1049
 		$cursor->closeCursor();
1050 1050
 
Please login to merge, or discard this patch.
Indentation   +983 added lines, -983 removed lines patch added patch discarded remove patch
@@ -47,1020 +47,1020 @@
 block discarded – undo
47 47
  */
48 48
 class DefaultShareProvider implements IShareProvider {
49 49
 
50
-	// Special share type for user modified group shares
51
-	const SHARE_TYPE_USERGROUP = 2;
52
-
53
-	/** @var IDBConnection */
54
-	private $dbConn;
55
-
56
-	/** @var IUserManager */
57
-	private $userManager;
58
-
59
-	/** @var IGroupManager */
60
-	private $groupManager;
61
-
62
-	/** @var IRootFolder */
63
-	private $rootFolder;
64
-
65
-	/**
66
-	 * DefaultShareProvider constructor.
67
-	 *
68
-	 * @param IDBConnection $connection
69
-	 * @param IUserManager $userManager
70
-	 * @param IGroupManager $groupManager
71
-	 * @param IRootFolder $rootFolder
72
-	 */
73
-	public function __construct(
74
-			IDBConnection $connection,
75
-			IUserManager $userManager,
76
-			IGroupManager $groupManager,
77
-			IRootFolder $rootFolder) {
78
-		$this->dbConn = $connection;
79
-		$this->userManager = $userManager;
80
-		$this->groupManager = $groupManager;
81
-		$this->rootFolder = $rootFolder;
82
-	}
83
-
84
-	/**
85
-	 * Return the identifier of this provider.
86
-	 *
87
-	 * @return string Containing only [a-zA-Z0-9]
88
-	 */
89
-	public function identifier() {
90
-		return 'ocinternal';
91
-	}
92
-
93
-	/**
94
-	 * Share a path
95
-	 *
96
-	 * @param \OCP\Share\IShare $share
97
-	 * @return \OCP\Share\IShare The share object
98
-	 * @throws ShareNotFound
99
-	 * @throws \Exception
100
-	 */
101
-	public function create(\OCP\Share\IShare $share) {
102
-		$qb = $this->dbConn->getQueryBuilder();
103
-
104
-		$qb->insert('share');
105
-		$qb->setValue('share_type', $qb->createNamedParameter($share->getShareType()));
106
-
107
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
108
-			//Set the UID of the user we share with
109
-			$qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
110
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
111
-			//Set the GID of the group we share with
112
-			$qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
113
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
114
-			//Set the token of the share
115
-			$qb->setValue('token', $qb->createNamedParameter($share->getToken()));
116
-
117
-			//If a password is set store it
118
-			if ($share->getPassword() !== null) {
119
-				$qb->setValue('share_with', $qb->createNamedParameter($share->getPassword()));
120
-			}
121
-
122
-			//If an expiration date is set store it
123
-			if ($share->getExpirationDate() !== null) {
124
-				$qb->setValue('expiration', $qb->createNamedParameter($share->getExpirationDate(), 'datetime'));
125
-			}
126
-
127
-			if (method_exists($share, 'getParent')) {
128
-				$qb->setValue('parent', $qb->createNamedParameter($share->getParent()));
129
-			}
130
-		} else {
131
-			throw new \Exception('invalid share type!');
132
-		}
133
-
134
-		// Set what is shares
135
-		$qb->setValue('item_type', $qb->createParameter('itemType'));
136
-		if ($share->getNode() instanceof \OCP\Files\File) {
137
-			$qb->setParameter('itemType', 'file');
138
-		} else {
139
-			$qb->setParameter('itemType', 'folder');
140
-		}
141
-
142
-		// Set the file id
143
-		$qb->setValue('item_source', $qb->createNamedParameter($share->getNode()->getId()));
144
-		$qb->setValue('file_source', $qb->createNamedParameter($share->getNode()->getId()));
145
-
146
-		// set the permissions
147
-		$qb->setValue('permissions', $qb->createNamedParameter($share->getPermissions()));
148
-
149
-		// Set who created this share
150
-		$qb->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy()));
151
-
152
-		// Set who is the owner of this file/folder (and this the owner of the share)
153
-		$qb->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner()));
154
-
155
-		// Set the file target
156
-		$qb->setValue('file_target', $qb->createNamedParameter($share->getTarget()));
157
-
158
-		// Set the time this share was created
159
-		$qb->setValue('stime', $qb->createNamedParameter(time()));
160
-
161
-		// insert the data and fetch the id of the share
162
-		$this->dbConn->beginTransaction();
163
-		$qb->execute();
164
-		$id = $this->dbConn->lastInsertId('*PREFIX*share');
165
-
166
-		// Now fetch the inserted share and create a complete share object
167
-		$qb = $this->dbConn->getQueryBuilder();
168
-		$qb->select('*')
169
-			->from('share')
170
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
171
-
172
-		$cursor = $qb->execute();
173
-		$data = $cursor->fetch();
174
-		$this->dbConn->commit();
175
-		$cursor->closeCursor();
176
-
177
-		if ($data === false) {
178
-			throw new ShareNotFound();
179
-		}
180
-
181
-		$share = $this->createShare($data);
182
-		return $share;
183
-	}
184
-
185
-	/**
186
-	 * Update a share
187
-	 *
188
-	 * @param \OCP\Share\IShare $share
189
-	 * @return \OCP\Share\IShare The share object
190
-	 */
191
-	public function update(\OCP\Share\IShare $share) {
192
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
193
-			/*
50
+    // Special share type for user modified group shares
51
+    const SHARE_TYPE_USERGROUP = 2;
52
+
53
+    /** @var IDBConnection */
54
+    private $dbConn;
55
+
56
+    /** @var IUserManager */
57
+    private $userManager;
58
+
59
+    /** @var IGroupManager */
60
+    private $groupManager;
61
+
62
+    /** @var IRootFolder */
63
+    private $rootFolder;
64
+
65
+    /**
66
+     * DefaultShareProvider constructor.
67
+     *
68
+     * @param IDBConnection $connection
69
+     * @param IUserManager $userManager
70
+     * @param IGroupManager $groupManager
71
+     * @param IRootFolder $rootFolder
72
+     */
73
+    public function __construct(
74
+            IDBConnection $connection,
75
+            IUserManager $userManager,
76
+            IGroupManager $groupManager,
77
+            IRootFolder $rootFolder) {
78
+        $this->dbConn = $connection;
79
+        $this->userManager = $userManager;
80
+        $this->groupManager = $groupManager;
81
+        $this->rootFolder = $rootFolder;
82
+    }
83
+
84
+    /**
85
+     * Return the identifier of this provider.
86
+     *
87
+     * @return string Containing only [a-zA-Z0-9]
88
+     */
89
+    public function identifier() {
90
+        return 'ocinternal';
91
+    }
92
+
93
+    /**
94
+     * Share a path
95
+     *
96
+     * @param \OCP\Share\IShare $share
97
+     * @return \OCP\Share\IShare The share object
98
+     * @throws ShareNotFound
99
+     * @throws \Exception
100
+     */
101
+    public function create(\OCP\Share\IShare $share) {
102
+        $qb = $this->dbConn->getQueryBuilder();
103
+
104
+        $qb->insert('share');
105
+        $qb->setValue('share_type', $qb->createNamedParameter($share->getShareType()));
106
+
107
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
108
+            //Set the UID of the user we share with
109
+            $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
110
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
111
+            //Set the GID of the group we share with
112
+            $qb->setValue('share_with', $qb->createNamedParameter($share->getSharedWith()));
113
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
114
+            //Set the token of the share
115
+            $qb->setValue('token', $qb->createNamedParameter($share->getToken()));
116
+
117
+            //If a password is set store it
118
+            if ($share->getPassword() !== null) {
119
+                $qb->setValue('share_with', $qb->createNamedParameter($share->getPassword()));
120
+            }
121
+
122
+            //If an expiration date is set store it
123
+            if ($share->getExpirationDate() !== null) {
124
+                $qb->setValue('expiration', $qb->createNamedParameter($share->getExpirationDate(), 'datetime'));
125
+            }
126
+
127
+            if (method_exists($share, 'getParent')) {
128
+                $qb->setValue('parent', $qb->createNamedParameter($share->getParent()));
129
+            }
130
+        } else {
131
+            throw new \Exception('invalid share type!');
132
+        }
133
+
134
+        // Set what is shares
135
+        $qb->setValue('item_type', $qb->createParameter('itemType'));
136
+        if ($share->getNode() instanceof \OCP\Files\File) {
137
+            $qb->setParameter('itemType', 'file');
138
+        } else {
139
+            $qb->setParameter('itemType', 'folder');
140
+        }
141
+
142
+        // Set the file id
143
+        $qb->setValue('item_source', $qb->createNamedParameter($share->getNode()->getId()));
144
+        $qb->setValue('file_source', $qb->createNamedParameter($share->getNode()->getId()));
145
+
146
+        // set the permissions
147
+        $qb->setValue('permissions', $qb->createNamedParameter($share->getPermissions()));
148
+
149
+        // Set who created this share
150
+        $qb->setValue('uid_initiator', $qb->createNamedParameter($share->getSharedBy()));
151
+
152
+        // Set who is the owner of this file/folder (and this the owner of the share)
153
+        $qb->setValue('uid_owner', $qb->createNamedParameter($share->getShareOwner()));
154
+
155
+        // Set the file target
156
+        $qb->setValue('file_target', $qb->createNamedParameter($share->getTarget()));
157
+
158
+        // Set the time this share was created
159
+        $qb->setValue('stime', $qb->createNamedParameter(time()));
160
+
161
+        // insert the data and fetch the id of the share
162
+        $this->dbConn->beginTransaction();
163
+        $qb->execute();
164
+        $id = $this->dbConn->lastInsertId('*PREFIX*share');
165
+
166
+        // Now fetch the inserted share and create a complete share object
167
+        $qb = $this->dbConn->getQueryBuilder();
168
+        $qb->select('*')
169
+            ->from('share')
170
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)));
171
+
172
+        $cursor = $qb->execute();
173
+        $data = $cursor->fetch();
174
+        $this->dbConn->commit();
175
+        $cursor->closeCursor();
176
+
177
+        if ($data === false) {
178
+            throw new ShareNotFound();
179
+        }
180
+
181
+        $share = $this->createShare($data);
182
+        return $share;
183
+    }
184
+
185
+    /**
186
+     * Update a share
187
+     *
188
+     * @param \OCP\Share\IShare $share
189
+     * @return \OCP\Share\IShare The share object
190
+     */
191
+    public function update(\OCP\Share\IShare $share) {
192
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
193
+            /*
194 194
 			 * We allow updating the recipient on user shares.
195 195
 			 */
196
-			$qb = $this->dbConn->getQueryBuilder();
197
-			$qb->update('share')
198
-				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
199
-				->set('share_with', $qb->createNamedParameter($share->getSharedWith()))
200
-				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
201
-				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
202
-				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
203
-				->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
204
-				->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
205
-				->execute();
206
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
207
-			$qb = $this->dbConn->getQueryBuilder();
208
-			$qb->update('share')
209
-				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
210
-				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
211
-				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
212
-				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
213
-				->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
214
-				->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
215
-				->execute();
216
-
217
-			/*
196
+            $qb = $this->dbConn->getQueryBuilder();
197
+            $qb->update('share')
198
+                ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
199
+                ->set('share_with', $qb->createNamedParameter($share->getSharedWith()))
200
+                ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
201
+                ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
202
+                ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
203
+                ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
204
+                ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
205
+                ->execute();
206
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
207
+            $qb = $this->dbConn->getQueryBuilder();
208
+            $qb->update('share')
209
+                ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
210
+                ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
211
+                ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
212
+                ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
213
+                ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
214
+                ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
215
+                ->execute();
216
+
217
+            /*
218 218
 			 * Update all user defined group shares
219 219
 			 */
220
-			$qb = $this->dbConn->getQueryBuilder();
221
-			$qb->update('share')
222
-				->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
223
-				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
224
-				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
225
-				->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
226
-				->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
227
-				->execute();
228
-
229
-			/*
220
+            $qb = $this->dbConn->getQueryBuilder();
221
+            $qb->update('share')
222
+                ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
223
+                ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
224
+                ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
225
+                ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
226
+                ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
227
+                ->execute();
228
+
229
+            /*
230 230
 			 * Now update the permissions for all children that have not set it to 0
231 231
 			 */
232
-			$qb = $this->dbConn->getQueryBuilder();
233
-			$qb->update('share')
234
-				->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
235
-				->andWhere($qb->expr()->neq('permissions', $qb->createNamedParameter(0)))
236
-				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
237
-				->execute();
238
-
239
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
240
-			$qb = $this->dbConn->getQueryBuilder();
241
-			$qb->update('share')
242
-				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
243
-				->set('share_with', $qb->createNamedParameter($share->getPassword()))
244
-				->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
245
-				->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
246
-				->set('permissions', $qb->createNamedParameter($share->getPermissions()))
247
-				->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
248
-				->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
249
-				->set('token', $qb->createNamedParameter($share->getToken()))
250
-				->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
251
-				->execute();
252
-		}
253
-
254
-		return $share;
255
-	}
256
-
257
-	/**
258
-	 * Get all children of this share
259
-	 * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
260
-	 *
261
-	 * @param \OCP\Share\IShare $parent
262
-	 * @return \OCP\Share\IShare[]
263
-	 */
264
-	public function getChildren(\OCP\Share\IShare $parent) {
265
-		$children = [];
266
-
267
-		$qb = $this->dbConn->getQueryBuilder();
268
-		$qb->select('*')
269
-			->from('share')
270
-			->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
271
-			->andWhere(
272
-				$qb->expr()->in(
273
-					'share_type',
274
-					$qb->createNamedParameter([
275
-						\OCP\Share::SHARE_TYPE_USER,
276
-						\OCP\Share::SHARE_TYPE_GROUP,
277
-						\OCP\Share::SHARE_TYPE_LINK,
278
-					], IQueryBuilder::PARAM_INT_ARRAY)
279
-				)
280
-			)
281
-			->andWhere($qb->expr()->orX(
282
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
283
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
284
-			))
285
-			->orderBy('id');
286
-
287
-		$cursor = $qb->execute();
288
-		while($data = $cursor->fetch()) {
289
-			$children[] = $this->createShare($data);
290
-		}
291
-		$cursor->closeCursor();
292
-
293
-		return $children;
294
-	}
295
-
296
-	/**
297
-	 * Delete a share
298
-	 *
299
-	 * @param \OCP\Share\IShare $share
300
-	 */
301
-	public function delete(\OCP\Share\IShare $share) {
302
-		$qb = $this->dbConn->getQueryBuilder();
303
-		$qb->delete('share')
304
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())));
305
-
306
-		/*
232
+            $qb = $this->dbConn->getQueryBuilder();
233
+            $qb->update('share')
234
+                ->where($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
235
+                ->andWhere($qb->expr()->neq('permissions', $qb->createNamedParameter(0)))
236
+                ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
237
+                ->execute();
238
+
239
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
240
+            $qb = $this->dbConn->getQueryBuilder();
241
+            $qb->update('share')
242
+                ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
243
+                ->set('share_with', $qb->createNamedParameter($share->getPassword()))
244
+                ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner()))
245
+                ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy()))
246
+                ->set('permissions', $qb->createNamedParameter($share->getPermissions()))
247
+                ->set('item_source', $qb->createNamedParameter($share->getNode()->getId()))
248
+                ->set('file_source', $qb->createNamedParameter($share->getNode()->getId()))
249
+                ->set('token', $qb->createNamedParameter($share->getToken()))
250
+                ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE))
251
+                ->execute();
252
+        }
253
+
254
+        return $share;
255
+    }
256
+
257
+    /**
258
+     * Get all children of this share
259
+     * FIXME: remove once https://github.com/owncloud/core/pull/21660 is in
260
+     *
261
+     * @param \OCP\Share\IShare $parent
262
+     * @return \OCP\Share\IShare[]
263
+     */
264
+    public function getChildren(\OCP\Share\IShare $parent) {
265
+        $children = [];
266
+
267
+        $qb = $this->dbConn->getQueryBuilder();
268
+        $qb->select('*')
269
+            ->from('share')
270
+            ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId())))
271
+            ->andWhere(
272
+                $qb->expr()->in(
273
+                    'share_type',
274
+                    $qb->createNamedParameter([
275
+                        \OCP\Share::SHARE_TYPE_USER,
276
+                        \OCP\Share::SHARE_TYPE_GROUP,
277
+                        \OCP\Share::SHARE_TYPE_LINK,
278
+                    ], IQueryBuilder::PARAM_INT_ARRAY)
279
+                )
280
+            )
281
+            ->andWhere($qb->expr()->orX(
282
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
283
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
284
+            ))
285
+            ->orderBy('id');
286
+
287
+        $cursor = $qb->execute();
288
+        while($data = $cursor->fetch()) {
289
+            $children[] = $this->createShare($data);
290
+        }
291
+        $cursor->closeCursor();
292
+
293
+        return $children;
294
+    }
295
+
296
+    /**
297
+     * Delete a share
298
+     *
299
+     * @param \OCP\Share\IShare $share
300
+     */
301
+    public function delete(\OCP\Share\IShare $share) {
302
+        $qb = $this->dbConn->getQueryBuilder();
303
+        $qb->delete('share')
304
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())));
305
+
306
+        /*
307 307
 		 * If the share is a group share delete all possible
308 308
 		 * user defined groups shares.
309 309
 		 */
310
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
311
-			$qb->orWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())));
312
-		}
313
-
314
-		$qb->execute();
315
-	}
316
-
317
-	/**
318
-	 * Unshare a share from the recipient. If this is a group share
319
-	 * this means we need a special entry in the share db.
320
-	 *
321
-	 * @param \OCP\Share\IShare $share
322
-	 * @param string $recipient UserId of recipient
323
-	 * @throws BackendError
324
-	 * @throws ProviderException
325
-	 */
326
-	public function deleteFromSelf(\OCP\Share\IShare $share, $recipient) {
327
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
328
-
329
-			$group = $this->groupManager->get($share->getSharedWith());
330
-			$user = $this->userManager->get($recipient);
331
-
332
-			if (!$group->inGroup($user)) {
333
-				throw new ProviderException('Recipient not in receiving group');
334
-			}
335
-
336
-			// Try to fetch user specific share
337
-			$qb = $this->dbConn->getQueryBuilder();
338
-			$stmt = $qb->select('*')
339
-				->from('share')
340
-				->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
341
-				->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))
342
-				->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
343
-				->andWhere($qb->expr()->orX(
344
-					$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
345
-					$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
346
-				))
347
-				->execute();
348
-
349
-			$data = $stmt->fetch();
350
-
351
-			/*
310
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
311
+            $qb->orWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())));
312
+        }
313
+
314
+        $qb->execute();
315
+    }
316
+
317
+    /**
318
+     * Unshare a share from the recipient. If this is a group share
319
+     * this means we need a special entry in the share db.
320
+     *
321
+     * @param \OCP\Share\IShare $share
322
+     * @param string $recipient UserId of recipient
323
+     * @throws BackendError
324
+     * @throws ProviderException
325
+     */
326
+    public function deleteFromSelf(\OCP\Share\IShare $share, $recipient) {
327
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
328
+
329
+            $group = $this->groupManager->get($share->getSharedWith());
330
+            $user = $this->userManager->get($recipient);
331
+
332
+            if (!$group->inGroup($user)) {
333
+                throw new ProviderException('Recipient not in receiving group');
334
+            }
335
+
336
+            // Try to fetch user specific share
337
+            $qb = $this->dbConn->getQueryBuilder();
338
+            $stmt = $qb->select('*')
339
+                ->from('share')
340
+                ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
341
+                ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))
342
+                ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
343
+                ->andWhere($qb->expr()->orX(
344
+                    $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
345
+                    $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
346
+                ))
347
+                ->execute();
348
+
349
+            $data = $stmt->fetch();
350
+
351
+            /*
352 352
 			 * Check if there already is a user specific group share.
353 353
 			 * If there is update it (if required).
354 354
 			 */
355
-			if ($data === false) {
356
-				$qb = $this->dbConn->getQueryBuilder();
357
-
358
-				$type = $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder';
359
-
360
-				//Insert new share
361
-				$qb->insert('share')
362
-					->values([
363
-						'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
364
-						'share_with' => $qb->createNamedParameter($recipient),
365
-						'uid_owner' => $qb->createNamedParameter($share->getShareOwner()),
366
-						'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()),
367
-						'parent' => $qb->createNamedParameter($share->getId()),
368
-						'item_type' => $qb->createNamedParameter($type),
369
-						'item_source' => $qb->createNamedParameter($share->getNode()->getId()),
370
-						'file_source' => $qb->createNamedParameter($share->getNode()->getId()),
371
-						'file_target' => $qb->createNamedParameter($share->getTarget()),
372
-						'permissions' => $qb->createNamedParameter(0),
373
-						'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
374
-					])->execute();
375
-
376
-			} else if ($data['permissions'] !== 0) {
377
-
378
-				// Update existing usergroup share
379
-				$qb = $this->dbConn->getQueryBuilder();
380
-				$qb->update('share')
381
-					->set('permissions', $qb->createNamedParameter(0))
382
-					->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
383
-					->execute();
384
-			}
385
-
386
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
387
-
388
-			if ($share->getSharedWith() !== $recipient) {
389
-				throw new ProviderException('Recipient does not match');
390
-			}
391
-
392
-			// We can just delete user and link shares
393
-			$this->delete($share);
394
-		} else {
395
-			throw new ProviderException('Invalid shareType');
396
-		}
397
-	}
398
-
399
-	/**
400
-	 * @inheritdoc
401
-	 */
402
-	public function move(\OCP\Share\IShare $share, $recipient) {
403
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
404
-			// Just update the target
405
-			$qb = $this->dbConn->getQueryBuilder();
406
-			$qb->update('share')
407
-				->set('file_target', $qb->createNamedParameter($share->getTarget()))
408
-				->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
409
-				->execute();
410
-
411
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
412
-
413
-			// Check if there is a usergroup share
414
-			$qb = $this->dbConn->getQueryBuilder();
415
-			$stmt = $qb->select('id')
416
-				->from('share')
417
-				->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
418
-				->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))
419
-				->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
420
-				->andWhere($qb->expr()->orX(
421
-					$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
422
-					$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
423
-				))
424
-				->setMaxResults(1)
425
-				->execute();
426
-
427
-			$data = $stmt->fetch();
428
-			$stmt->closeCursor();
429
-
430
-			if ($data === false) {
431
-				// No usergroup share yet. Create one.
432
-				$qb = $this->dbConn->getQueryBuilder();
433
-				$qb->insert('share')
434
-					->values([
435
-						'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
436
-						'share_with' => $qb->createNamedParameter($recipient),
437
-						'uid_owner' => $qb->createNamedParameter($share->getShareOwner()),
438
-						'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()),
439
-						'parent' => $qb->createNamedParameter($share->getId()),
440
-						'item_type' => $qb->createNamedParameter($share->getNode() instanceof File ? 'file' : 'folder'),
441
-						'item_source' => $qb->createNamedParameter($share->getNode()->getId()),
442
-						'file_source' => $qb->createNamedParameter($share->getNode()->getId()),
443
-						'file_target' => $qb->createNamedParameter($share->getTarget()),
444
-						'permissions' => $qb->createNamedParameter($share->getPermissions()),
445
-						'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
446
-					])->execute();
447
-			} else {
448
-				// Already a usergroup share. Update it.
449
-				$qb = $this->dbConn->getQueryBuilder();
450
-				$qb->update('share')
451
-					->set('file_target', $qb->createNamedParameter($share->getTarget()))
452
-					->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
453
-					->execute();
454
-			}
455
-		}
456
-
457
-		return $share;
458
-	}
459
-
460
-	public function getSharesInFolder($userId, Folder $node, $reshares) {
461
-		$qb = $this->dbConn->getQueryBuilder();
462
-		$qb->select('*')
463
-			->from('share', 's')
464
-			->andWhere($qb->expr()->orX(
465
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
466
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
467
-			));
468
-
469
-		$qb->andWhere($qb->expr()->orX(
470
-			$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)),
471
-			$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)),
472
-			$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK))
473
-		));
474
-
475
-		/**
476
-		 * Reshares for this user are shares where they are the owner.
477
-		 */
478
-		if ($reshares === false) {
479
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
480
-		} else {
481
-			$qb->andWhere(
482
-				$qb->expr()->orX(
483
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
484
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
485
-				)
486
-			);
487
-		}
488
-
489
-		$qb->innerJoin('s', 'filecache' ,'f', 's.file_source = f.fileid');
490
-		$qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
491
-
492
-		$qb->orderBy('id');
493
-
494
-		$cursor = $qb->execute();
495
-		$shares = [];
496
-		while ($data = $cursor->fetch()) {
497
-			$shares[$data['fileid']][] = $this->createShare($data);
498
-		}
499
-		$cursor->closeCursor();
500
-
501
-		return $shares;
502
-	}
503
-
504
-	/**
505
-	 * @inheritdoc
506
-	 */
507
-	public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
508
-		$qb = $this->dbConn->getQueryBuilder();
509
-		$qb->select('*')
510
-			->from('share')
511
-			->andWhere($qb->expr()->orX(
512
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
513
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
514
-			));
515
-
516
-		$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
517
-
518
-		/**
519
-		 * Reshares for this user are shares where they are the owner.
520
-		 */
521
-		if ($reshares === false) {
522
-			$qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
523
-		} else {
524
-			$qb->andWhere(
525
-				$qb->expr()->orX(
526
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
527
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
528
-				)
529
-			);
530
-		}
531
-
532
-		if ($node !== null) {
533
-			$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
534
-		}
535
-
536
-		if ($limit !== -1) {
537
-			$qb->setMaxResults($limit);
538
-		}
539
-
540
-		$qb->setFirstResult($offset);
541
-		$qb->orderBy('id');
542
-
543
-		$cursor = $qb->execute();
544
-		$shares = [];
545
-		while($data = $cursor->fetch()) {
546
-			$shares[] = $this->createShare($data);
547
-		}
548
-		$cursor->closeCursor();
549
-
550
-		return $shares;
551
-	}
552
-
553
-	/**
554
-	 * @inheritdoc
555
-	 */
556
-	public function getShareById($id, $recipientId = null) {
557
-		$qb = $this->dbConn->getQueryBuilder();
558
-
559
-		$qb->select('*')
560
-			->from('share')
561
-			->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
562
-			->andWhere(
563
-				$qb->expr()->in(
564
-					'share_type',
565
-					$qb->createNamedParameter([
566
-						\OCP\Share::SHARE_TYPE_USER,
567
-						\OCP\Share::SHARE_TYPE_GROUP,
568
-						\OCP\Share::SHARE_TYPE_LINK,
569
-					], IQueryBuilder::PARAM_INT_ARRAY)
570
-				)
571
-			)
572
-			->andWhere($qb->expr()->orX(
573
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
574
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
575
-			));
576
-
577
-		$cursor = $qb->execute();
578
-		$data = $cursor->fetch();
579
-		$cursor->closeCursor();
580
-
581
-		if ($data === false) {
582
-			throw new ShareNotFound();
583
-		}
584
-
585
-		try {
586
-			$share = $this->createShare($data);
587
-		} catch (InvalidShare $e) {
588
-			throw new ShareNotFound();
589
-		}
590
-
591
-		// If the recipient is set for a group share resolve to that user
592
-		if ($recipientId !== null && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
593
-			$share = $this->resolveGroupShares([$share], $recipientId)[0];
594
-		}
595
-
596
-		return $share;
597
-	}
598
-
599
-	/**
600
-	 * Get shares for a given path
601
-	 *
602
-	 * @param \OCP\Files\Node $path
603
-	 * @return \OCP\Share\IShare[]
604
-	 */
605
-	public function getSharesByPath(Node $path) {
606
-		$qb = $this->dbConn->getQueryBuilder();
607
-
608
-		$cursor = $qb->select('*')
609
-			->from('share')
610
-			->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
611
-			->andWhere(
612
-				$qb->expr()->orX(
613
-					$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)),
614
-					$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))
615
-				)
616
-			)
617
-			->andWhere($qb->expr()->orX(
618
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
619
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
620
-			))
621
-			->execute();
622
-
623
-		$shares = [];
624
-		while($data = $cursor->fetch()) {
625
-			$shares[] = $this->createShare($data);
626
-		}
627
-		$cursor->closeCursor();
628
-
629
-		return $shares;
630
-	}
631
-
632
-	/**
633
-	 * Returns whether the given database result can be interpreted as
634
-	 * a share with accessible file (not trashed, not deleted)
635
-	 */
636
-	private function isAccessibleResult($data) {
637
-		// exclude shares leading to deleted file entries
638
-		if ($data['fileid'] === null) {
639
-			return false;
640
-		}
641
-
642
-		// exclude shares leading to trashbin on home storages
643
-		$pathSections = explode('/', $data['path'], 2);
644
-		// FIXME: would not detect rare md5'd home storage case properly
645
-		if ($pathSections[0] !== 'files' 
646
-		    	&& in_array(explode(':', $data['storage_string_id'], 2)[0], array('home', 'object'))) {
647
-			return false;
648
-		}
649
-		return true;
650
-	}
651
-
652
-	/**
653
-	 * @inheritdoc
654
-	 */
655
-	public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
656
-		/** @var Share[] $shares */
657
-		$shares = [];
658
-
659
-		if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
660
-			//Get shares directly with this user
661
-			$qb = $this->dbConn->getQueryBuilder();
662
-			$qb->select('s.*',
663
-				'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash',
664
-				'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime',
665
-				'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum'
666
-			)
667
-				->selectAlias('st.id', 'storage_string_id')
668
-				->from('share', 's')
669
-				->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
670
-				->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'));
671
-
672
-			// Order by id
673
-			$qb->orderBy('s.id');
674
-
675
-			// Set limit and offset
676
-			if ($limit !== -1) {
677
-				$qb->setMaxResults($limit);
678
-			}
679
-			$qb->setFirstResult($offset);
680
-
681
-			$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)))
682
-				->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
683
-				->andWhere($qb->expr()->orX(
684
-					$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
685
-					$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
686
-				));
687
-
688
-			// Filter by node if provided
689
-			if ($node !== null) {
690
-				$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
691
-			}
692
-
693
-			$cursor = $qb->execute();
694
-
695
-			while($data = $cursor->fetch()) {
696
-				if ($this->isAccessibleResult($data)) {
697
-					$shares[] = $this->createShare($data);
698
-				}
699
-			}
700
-			$cursor->closeCursor();
701
-
702
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
703
-			$user = $this->userManager->get($userId);
704
-			$allGroups = $this->groupManager->getUserGroups($user);
705
-
706
-			/** @var Share[] $shares2 */
707
-			$shares2 = [];
708
-
709
-			$start = 0;
710
-			while(true) {
711
-				$groups = array_slice($allGroups, $start, 100);
712
-				$start += 100;
713
-
714
-				if ($groups === []) {
715
-					break;
716
-				}
717
-
718
-				$qb = $this->dbConn->getQueryBuilder();
719
-				$qb->select('s.*',
720
-					'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash',
721
-					'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime',
722
-					'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum'
723
-				)
724
-					->selectAlias('st.id', 'storage_string_id')
725
-					->from('share', 's')
726
-					->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
727
-					->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'))
728
-					->orderBy('s.id')
729
-					->setFirstResult(0);
730
-
731
-				if ($limit !== -1) {
732
-					$qb->setMaxResults($limit - count($shares));
733
-				}
734
-
735
-				// Filter by node if provided
736
-				if ($node !== null) {
737
-					$qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
738
-				}
739
-
740
-				$groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups);
741
-
742
-				$qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
743
-					->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter(
744
-						$groups,
745
-						IQueryBuilder::PARAM_STR_ARRAY
746
-					)))
747
-					->andWhere($qb->expr()->orX(
748
-						$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
749
-						$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
750
-					));
751
-
752
-				$cursor = $qb->execute();
753
-				while($data = $cursor->fetch()) {
754
-					if ($offset > 0) {
755
-						$offset--;
756
-						continue;
757
-					}
758
-
759
-					if ($this->isAccessibleResult($data)) {
760
-						$shares2[] = $this->createShare($data);
761
-					}
762
-				}
763
-				$cursor->closeCursor();
764
-			}
765
-
766
-			/*
355
+            if ($data === false) {
356
+                $qb = $this->dbConn->getQueryBuilder();
357
+
358
+                $type = $share->getNode() instanceof \OCP\Files\File ? 'file' : 'folder';
359
+
360
+                //Insert new share
361
+                $qb->insert('share')
362
+                    ->values([
363
+                        'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
364
+                        'share_with' => $qb->createNamedParameter($recipient),
365
+                        'uid_owner' => $qb->createNamedParameter($share->getShareOwner()),
366
+                        'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()),
367
+                        'parent' => $qb->createNamedParameter($share->getId()),
368
+                        'item_type' => $qb->createNamedParameter($type),
369
+                        'item_source' => $qb->createNamedParameter($share->getNode()->getId()),
370
+                        'file_source' => $qb->createNamedParameter($share->getNode()->getId()),
371
+                        'file_target' => $qb->createNamedParameter($share->getTarget()),
372
+                        'permissions' => $qb->createNamedParameter(0),
373
+                        'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
374
+                    ])->execute();
375
+
376
+            } else if ($data['permissions'] !== 0) {
377
+
378
+                // Update existing usergroup share
379
+                $qb = $this->dbConn->getQueryBuilder();
380
+                $qb->update('share')
381
+                    ->set('permissions', $qb->createNamedParameter(0))
382
+                    ->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
383
+                    ->execute();
384
+            }
385
+
386
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
387
+
388
+            if ($share->getSharedWith() !== $recipient) {
389
+                throw new ProviderException('Recipient does not match');
390
+            }
391
+
392
+            // We can just delete user and link shares
393
+            $this->delete($share);
394
+        } else {
395
+            throw new ProviderException('Invalid shareType');
396
+        }
397
+    }
398
+
399
+    /**
400
+     * @inheritdoc
401
+     */
402
+    public function move(\OCP\Share\IShare $share, $recipient) {
403
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
404
+            // Just update the target
405
+            $qb = $this->dbConn->getQueryBuilder();
406
+            $qb->update('share')
407
+                ->set('file_target', $qb->createNamedParameter($share->getTarget()))
408
+                ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId())))
409
+                ->execute();
410
+
411
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
412
+
413
+            // Check if there is a usergroup share
414
+            $qb = $this->dbConn->getQueryBuilder();
415
+            $stmt = $qb->select('id')
416
+                ->from('share')
417
+                ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
418
+                ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($recipient)))
419
+                ->andWhere($qb->expr()->eq('parent', $qb->createNamedParameter($share->getId())))
420
+                ->andWhere($qb->expr()->orX(
421
+                    $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
422
+                    $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
423
+                ))
424
+                ->setMaxResults(1)
425
+                ->execute();
426
+
427
+            $data = $stmt->fetch();
428
+            $stmt->closeCursor();
429
+
430
+            if ($data === false) {
431
+                // No usergroup share yet. Create one.
432
+                $qb = $this->dbConn->getQueryBuilder();
433
+                $qb->insert('share')
434
+                    ->values([
435
+                        'share_type' => $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP),
436
+                        'share_with' => $qb->createNamedParameter($recipient),
437
+                        'uid_owner' => $qb->createNamedParameter($share->getShareOwner()),
438
+                        'uid_initiator' => $qb->createNamedParameter($share->getSharedBy()),
439
+                        'parent' => $qb->createNamedParameter($share->getId()),
440
+                        'item_type' => $qb->createNamedParameter($share->getNode() instanceof File ? 'file' : 'folder'),
441
+                        'item_source' => $qb->createNamedParameter($share->getNode()->getId()),
442
+                        'file_source' => $qb->createNamedParameter($share->getNode()->getId()),
443
+                        'file_target' => $qb->createNamedParameter($share->getTarget()),
444
+                        'permissions' => $qb->createNamedParameter($share->getPermissions()),
445
+                        'stime' => $qb->createNamedParameter($share->getShareTime()->getTimestamp()),
446
+                    ])->execute();
447
+            } else {
448
+                // Already a usergroup share. Update it.
449
+                $qb = $this->dbConn->getQueryBuilder();
450
+                $qb->update('share')
451
+                    ->set('file_target', $qb->createNamedParameter($share->getTarget()))
452
+                    ->where($qb->expr()->eq('id', $qb->createNamedParameter($data['id'])))
453
+                    ->execute();
454
+            }
455
+        }
456
+
457
+        return $share;
458
+    }
459
+
460
+    public function getSharesInFolder($userId, Folder $node, $reshares) {
461
+        $qb = $this->dbConn->getQueryBuilder();
462
+        $qb->select('*')
463
+            ->from('share', 's')
464
+            ->andWhere($qb->expr()->orX(
465
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
466
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
467
+            ));
468
+
469
+        $qb->andWhere($qb->expr()->orX(
470
+            $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)),
471
+            $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)),
472
+            $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK))
473
+        ));
474
+
475
+        /**
476
+         * Reshares for this user are shares where they are the owner.
477
+         */
478
+        if ($reshares === false) {
479
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
480
+        } else {
481
+            $qb->andWhere(
482
+                $qb->expr()->orX(
483
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
484
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
485
+                )
486
+            );
487
+        }
488
+
489
+        $qb->innerJoin('s', 'filecache' ,'f', 's.file_source = f.fileid');
490
+        $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())));
491
+
492
+        $qb->orderBy('id');
493
+
494
+        $cursor = $qb->execute();
495
+        $shares = [];
496
+        while ($data = $cursor->fetch()) {
497
+            $shares[$data['fileid']][] = $this->createShare($data);
498
+        }
499
+        $cursor->closeCursor();
500
+
501
+        return $shares;
502
+    }
503
+
504
+    /**
505
+     * @inheritdoc
506
+     */
507
+    public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) {
508
+        $qb = $this->dbConn->getQueryBuilder();
509
+        $qb->select('*')
510
+            ->from('share')
511
+            ->andWhere($qb->expr()->orX(
512
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
513
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
514
+            ));
515
+
516
+        $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType)));
517
+
518
+        /**
519
+         * Reshares for this user are shares where they are the owner.
520
+         */
521
+        if ($reshares === false) {
522
+            $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)));
523
+        } else {
524
+            $qb->andWhere(
525
+                $qb->expr()->orX(
526
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)),
527
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))
528
+                )
529
+            );
530
+        }
531
+
532
+        if ($node !== null) {
533
+            $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
534
+        }
535
+
536
+        if ($limit !== -1) {
537
+            $qb->setMaxResults($limit);
538
+        }
539
+
540
+        $qb->setFirstResult($offset);
541
+        $qb->orderBy('id');
542
+
543
+        $cursor = $qb->execute();
544
+        $shares = [];
545
+        while($data = $cursor->fetch()) {
546
+            $shares[] = $this->createShare($data);
547
+        }
548
+        $cursor->closeCursor();
549
+
550
+        return $shares;
551
+    }
552
+
553
+    /**
554
+     * @inheritdoc
555
+     */
556
+    public function getShareById($id, $recipientId = null) {
557
+        $qb = $this->dbConn->getQueryBuilder();
558
+
559
+        $qb->select('*')
560
+            ->from('share')
561
+            ->where($qb->expr()->eq('id', $qb->createNamedParameter($id)))
562
+            ->andWhere(
563
+                $qb->expr()->in(
564
+                    'share_type',
565
+                    $qb->createNamedParameter([
566
+                        \OCP\Share::SHARE_TYPE_USER,
567
+                        \OCP\Share::SHARE_TYPE_GROUP,
568
+                        \OCP\Share::SHARE_TYPE_LINK,
569
+                    ], IQueryBuilder::PARAM_INT_ARRAY)
570
+                )
571
+            )
572
+            ->andWhere($qb->expr()->orX(
573
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
574
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
575
+            ));
576
+
577
+        $cursor = $qb->execute();
578
+        $data = $cursor->fetch();
579
+        $cursor->closeCursor();
580
+
581
+        if ($data === false) {
582
+            throw new ShareNotFound();
583
+        }
584
+
585
+        try {
586
+            $share = $this->createShare($data);
587
+        } catch (InvalidShare $e) {
588
+            throw new ShareNotFound();
589
+        }
590
+
591
+        // If the recipient is set for a group share resolve to that user
592
+        if ($recipientId !== null && $share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
593
+            $share = $this->resolveGroupShares([$share], $recipientId)[0];
594
+        }
595
+
596
+        return $share;
597
+    }
598
+
599
+    /**
600
+     * Get shares for a given path
601
+     *
602
+     * @param \OCP\Files\Node $path
603
+     * @return \OCP\Share\IShare[]
604
+     */
605
+    public function getSharesByPath(Node $path) {
606
+        $qb = $this->dbConn->getQueryBuilder();
607
+
608
+        $cursor = $qb->select('*')
609
+            ->from('share')
610
+            ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId())))
611
+            ->andWhere(
612
+                $qb->expr()->orX(
613
+                    $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)),
614
+                    $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP))
615
+                )
616
+            )
617
+            ->andWhere($qb->expr()->orX(
618
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
619
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
620
+            ))
621
+            ->execute();
622
+
623
+        $shares = [];
624
+        while($data = $cursor->fetch()) {
625
+            $shares[] = $this->createShare($data);
626
+        }
627
+        $cursor->closeCursor();
628
+
629
+        return $shares;
630
+    }
631
+
632
+    /**
633
+     * Returns whether the given database result can be interpreted as
634
+     * a share with accessible file (not trashed, not deleted)
635
+     */
636
+    private function isAccessibleResult($data) {
637
+        // exclude shares leading to deleted file entries
638
+        if ($data['fileid'] === null) {
639
+            return false;
640
+        }
641
+
642
+        // exclude shares leading to trashbin on home storages
643
+        $pathSections = explode('/', $data['path'], 2);
644
+        // FIXME: would not detect rare md5'd home storage case properly
645
+        if ($pathSections[0] !== 'files' 
646
+                && in_array(explode(':', $data['storage_string_id'], 2)[0], array('home', 'object'))) {
647
+            return false;
648
+        }
649
+        return true;
650
+    }
651
+
652
+    /**
653
+     * @inheritdoc
654
+     */
655
+    public function getSharedWith($userId, $shareType, $node, $limit, $offset) {
656
+        /** @var Share[] $shares */
657
+        $shares = [];
658
+
659
+        if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
660
+            //Get shares directly with this user
661
+            $qb = $this->dbConn->getQueryBuilder();
662
+            $qb->select('s.*',
663
+                'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash',
664
+                'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime',
665
+                'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum'
666
+            )
667
+                ->selectAlias('st.id', 'storage_string_id')
668
+                ->from('share', 's')
669
+                ->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
670
+                ->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'));
671
+
672
+            // Order by id
673
+            $qb->orderBy('s.id');
674
+
675
+            // Set limit and offset
676
+            if ($limit !== -1) {
677
+                $qb->setMaxResults($limit);
678
+            }
679
+            $qb->setFirstResult($offset);
680
+
681
+            $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)))
682
+                ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
683
+                ->andWhere($qb->expr()->orX(
684
+                    $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
685
+                    $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
686
+                ));
687
+
688
+            // Filter by node if provided
689
+            if ($node !== null) {
690
+                $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
691
+            }
692
+
693
+            $cursor = $qb->execute();
694
+
695
+            while($data = $cursor->fetch()) {
696
+                if ($this->isAccessibleResult($data)) {
697
+                    $shares[] = $this->createShare($data);
698
+                }
699
+            }
700
+            $cursor->closeCursor();
701
+
702
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
703
+            $user = $this->userManager->get($userId);
704
+            $allGroups = $this->groupManager->getUserGroups($user);
705
+
706
+            /** @var Share[] $shares2 */
707
+            $shares2 = [];
708
+
709
+            $start = 0;
710
+            while(true) {
711
+                $groups = array_slice($allGroups, $start, 100);
712
+                $start += 100;
713
+
714
+                if ($groups === []) {
715
+                    break;
716
+                }
717
+
718
+                $qb = $this->dbConn->getQueryBuilder();
719
+                $qb->select('s.*',
720
+                    'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash',
721
+                    'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime',
722
+                    'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum'
723
+                )
724
+                    ->selectAlias('st.id', 'storage_string_id')
725
+                    ->from('share', 's')
726
+                    ->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid'))
727
+                    ->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id'))
728
+                    ->orderBy('s.id')
729
+                    ->setFirstResult(0);
730
+
731
+                if ($limit !== -1) {
732
+                    $qb->setMaxResults($limit - count($shares));
733
+                }
734
+
735
+                // Filter by node if provided
736
+                if ($node !== null) {
737
+                    $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId())));
738
+                }
739
+
740
+                $groups = array_map(function(IGroup $group) { return $group->getGID(); }, $groups);
741
+
742
+                $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
743
+                    ->andWhere($qb->expr()->in('share_with', $qb->createNamedParameter(
744
+                        $groups,
745
+                        IQueryBuilder::PARAM_STR_ARRAY
746
+                    )))
747
+                    ->andWhere($qb->expr()->orX(
748
+                        $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
749
+                        $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
750
+                    ));
751
+
752
+                $cursor = $qb->execute();
753
+                while($data = $cursor->fetch()) {
754
+                    if ($offset > 0) {
755
+                        $offset--;
756
+                        continue;
757
+                    }
758
+
759
+                    if ($this->isAccessibleResult($data)) {
760
+                        $shares2[] = $this->createShare($data);
761
+                    }
762
+                }
763
+                $cursor->closeCursor();
764
+            }
765
+
766
+            /*
767 767
  			 * Resolve all group shares to user specific shares
768 768
  			 */
769
-			$shares = $this->resolveGroupShares($shares2, $userId);
770
-		} else {
771
-			throw new BackendError('Invalid backend');
772
-		}
773
-
774
-
775
-		return $shares;
776
-	}
777
-
778
-	/**
779
-	 * Get a share by token
780
-	 *
781
-	 * @param string $token
782
-	 * @return \OCP\Share\IShare
783
-	 * @throws ShareNotFound
784
-	 */
785
-	public function getShareByToken($token) {
786
-		$qb = $this->dbConn->getQueryBuilder();
787
-
788
-		$cursor = $qb->select('*')
789
-			->from('share')
790
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)))
791
-			->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
792
-			->andWhere($qb->expr()->orX(
793
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
794
-				$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
795
-			))
796
-			->execute();
797
-
798
-		$data = $cursor->fetch();
799
-
800
-		if ($data === false) {
801
-			throw new ShareNotFound();
802
-		}
803
-
804
-		try {
805
-			$share = $this->createShare($data);
806
-		} catch (InvalidShare $e) {
807
-			throw new ShareNotFound();
808
-		}
809
-
810
-		return $share;
811
-	}
812
-
813
-	/**
814
-	 * Create a share object from an database row
815
-	 *
816
-	 * @param mixed[] $data
817
-	 * @return \OCP\Share\IShare
818
-	 * @throws InvalidShare
819
-	 */
820
-	private function createShare($data) {
821
-		$share = new Share($this->rootFolder, $this->userManager);
822
-		$share->setId((int)$data['id'])
823
-			->setShareType((int)$data['share_type'])
824
-			->setPermissions((int)$data['permissions'])
825
-			->setTarget($data['file_target'])
826
-			->setMailSend((bool)$data['mail_send']);
827
-
828
-		$shareTime = new \DateTime();
829
-		$shareTime->setTimestamp((int)$data['stime']);
830
-		$share->setShareTime($shareTime);
831
-
832
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
833
-			$share->setSharedWith($data['share_with']);
834
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
835
-			$share->setSharedWith($data['share_with']);
836
-		} else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
837
-			$share->setPassword($data['share_with']);
838
-			$share->setToken($data['token']);
839
-		}
840
-
841
-		$share->setSharedBy($data['uid_initiator']);
842
-		$share->setShareOwner($data['uid_owner']);
843
-
844
-		$share->setNodeId((int)$data['file_source']);
845
-		$share->setNodeType($data['item_type']);
846
-
847
-		if ($data['expiration'] !== null) {
848
-			$expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
849
-			$share->setExpirationDate($expiration);
850
-		}
851
-
852
-		if (isset($data['f_permissions'])) {
853
-			$entryData = $data;
854
-			$entryData['permissions'] = $entryData['f_permissions'];
855
-			$entryData['parent'] = $entryData['f_parent'];;
856
-			$share->setNodeCacheEntry(Cache::cacheEntryFromData($entryData,
857
-				\OC::$server->getMimeTypeLoader()));
858
-		}
859
-
860
-		$share->setProviderId($this->identifier());
861
-
862
-		return $share;
863
-	}
864
-
865
-	/**
866
-	 * @param Share[] $shares
867
-	 * @param $userId
868
-	 * @return Share[] The updates shares if no update is found for a share return the original
869
-	 */
870
-	private function resolveGroupShares($shares, $userId) {
871
-		$result = [];
872
-
873
-		$start = 0;
874
-		while(true) {
875
-			/** @var Share[] $shareSlice */
876
-			$shareSlice = array_slice($shares, $start, 100);
877
-			$start += 100;
878
-
879
-			if ($shareSlice === []) {
880
-				break;
881
-			}
882
-
883
-			/** @var int[] $ids */
884
-			$ids = [];
885
-			/** @var Share[] $shareMap */
886
-			$shareMap = [];
887
-
888
-			foreach ($shareSlice as $share) {
889
-				$ids[] = (int)$share->getId();
890
-				$shareMap[$share->getId()] = $share;
891
-			}
892
-
893
-			$qb = $this->dbConn->getQueryBuilder();
894
-
895
-			$query = $qb->select('*')
896
-				->from('share')
897
-				->where($qb->expr()->in('parent', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
898
-				->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
899
-				->andWhere($qb->expr()->orX(
900
-					$qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
901
-					$qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
902
-				));
903
-
904
-			$stmt = $query->execute();
905
-
906
-			while($data = $stmt->fetch()) {
907
-				$shareMap[$data['parent']]->setPermissions((int)$data['permissions']);
908
-				$shareMap[$data['parent']]->setTarget($data['file_target']);
909
-			}
910
-
911
-			$stmt->closeCursor();
912
-
913
-			foreach ($shareMap as $share) {
914
-				$result[] = $share;
915
-			}
916
-		}
917
-
918
-		return $result;
919
-	}
920
-
921
-	/**
922
-	 * A user is deleted from the system
923
-	 * So clean up the relevant shares.
924
-	 *
925
-	 * @param string $uid
926
-	 * @param int $shareType
927
-	 */
928
-	public function userDeleted($uid, $shareType) {
929
-		$qb = $this->dbConn->getQueryBuilder();
930
-
931
-		$qb->delete('share');
932
-
933
-		if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
934
-			/*
769
+            $shares = $this->resolveGroupShares($shares2, $userId);
770
+        } else {
771
+            throw new BackendError('Invalid backend');
772
+        }
773
+
774
+
775
+        return $shares;
776
+    }
777
+
778
+    /**
779
+     * Get a share by token
780
+     *
781
+     * @param string $token
782
+     * @return \OCP\Share\IShare
783
+     * @throws ShareNotFound
784
+     */
785
+    public function getShareByToken($token) {
786
+        $qb = $this->dbConn->getQueryBuilder();
787
+
788
+        $cursor = $qb->select('*')
789
+            ->from('share')
790
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)))
791
+            ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token)))
792
+            ->andWhere($qb->expr()->orX(
793
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
794
+                $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
795
+            ))
796
+            ->execute();
797
+
798
+        $data = $cursor->fetch();
799
+
800
+        if ($data === false) {
801
+            throw new ShareNotFound();
802
+        }
803
+
804
+        try {
805
+            $share = $this->createShare($data);
806
+        } catch (InvalidShare $e) {
807
+            throw new ShareNotFound();
808
+        }
809
+
810
+        return $share;
811
+    }
812
+
813
+    /**
814
+     * Create a share object from an database row
815
+     *
816
+     * @param mixed[] $data
817
+     * @return \OCP\Share\IShare
818
+     * @throws InvalidShare
819
+     */
820
+    private function createShare($data) {
821
+        $share = new Share($this->rootFolder, $this->userManager);
822
+        $share->setId((int)$data['id'])
823
+            ->setShareType((int)$data['share_type'])
824
+            ->setPermissions((int)$data['permissions'])
825
+            ->setTarget($data['file_target'])
826
+            ->setMailSend((bool)$data['mail_send']);
827
+
828
+        $shareTime = new \DateTime();
829
+        $shareTime->setTimestamp((int)$data['stime']);
830
+        $share->setShareTime($shareTime);
831
+
832
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER) {
833
+            $share->setSharedWith($data['share_with']);
834
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP) {
835
+            $share->setSharedWith($data['share_with']);
836
+        } else if ($share->getShareType() === \OCP\Share::SHARE_TYPE_LINK) {
837
+            $share->setPassword($data['share_with']);
838
+            $share->setToken($data['token']);
839
+        }
840
+
841
+        $share->setSharedBy($data['uid_initiator']);
842
+        $share->setShareOwner($data['uid_owner']);
843
+
844
+        $share->setNodeId((int)$data['file_source']);
845
+        $share->setNodeType($data['item_type']);
846
+
847
+        if ($data['expiration'] !== null) {
848
+            $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']);
849
+            $share->setExpirationDate($expiration);
850
+        }
851
+
852
+        if (isset($data['f_permissions'])) {
853
+            $entryData = $data;
854
+            $entryData['permissions'] = $entryData['f_permissions'];
855
+            $entryData['parent'] = $entryData['f_parent'];;
856
+            $share->setNodeCacheEntry(Cache::cacheEntryFromData($entryData,
857
+                \OC::$server->getMimeTypeLoader()));
858
+        }
859
+
860
+        $share->setProviderId($this->identifier());
861
+
862
+        return $share;
863
+    }
864
+
865
+    /**
866
+     * @param Share[] $shares
867
+     * @param $userId
868
+     * @return Share[] The updates shares if no update is found for a share return the original
869
+     */
870
+    private function resolveGroupShares($shares, $userId) {
871
+        $result = [];
872
+
873
+        $start = 0;
874
+        while(true) {
875
+            /** @var Share[] $shareSlice */
876
+            $shareSlice = array_slice($shares, $start, 100);
877
+            $start += 100;
878
+
879
+            if ($shareSlice === []) {
880
+                break;
881
+            }
882
+
883
+            /** @var int[] $ids */
884
+            $ids = [];
885
+            /** @var Share[] $shareMap */
886
+            $shareMap = [];
887
+
888
+            foreach ($shareSlice as $share) {
889
+                $ids[] = (int)$share->getId();
890
+                $shareMap[$share->getId()] = $share;
891
+            }
892
+
893
+            $qb = $this->dbConn->getQueryBuilder();
894
+
895
+            $query = $qb->select('*')
896
+                ->from('share')
897
+                ->where($qb->expr()->in('parent', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)))
898
+                ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId)))
899
+                ->andWhere($qb->expr()->orX(
900
+                    $qb->expr()->eq('item_type', $qb->createNamedParameter('file')),
901
+                    $qb->expr()->eq('item_type', $qb->createNamedParameter('folder'))
902
+                ));
903
+
904
+            $stmt = $query->execute();
905
+
906
+            while($data = $stmt->fetch()) {
907
+                $shareMap[$data['parent']]->setPermissions((int)$data['permissions']);
908
+                $shareMap[$data['parent']]->setTarget($data['file_target']);
909
+            }
910
+
911
+            $stmt->closeCursor();
912
+
913
+            foreach ($shareMap as $share) {
914
+                $result[] = $share;
915
+            }
916
+        }
917
+
918
+        return $result;
919
+    }
920
+
921
+    /**
922
+     * A user is deleted from the system
923
+     * So clean up the relevant shares.
924
+     *
925
+     * @param string $uid
926
+     * @param int $shareType
927
+     */
928
+    public function userDeleted($uid, $shareType) {
929
+        $qb = $this->dbConn->getQueryBuilder();
930
+
931
+        $qb->delete('share');
932
+
933
+        if ($shareType === \OCP\Share::SHARE_TYPE_USER) {
934
+            /*
935 935
 			 * Delete all user shares that are owned by this user
936 936
 			 * or that are received by this user
937 937
 			 */
938 938
 
939
-			$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)));
939
+            $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_USER)));
940 940
 
941
-			$qb->andWhere(
942
-				$qb->expr()->orX(
943
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
944
-					$qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
945
-				)
946
-			);
947
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
948
-			/*
941
+            $qb->andWhere(
942
+                $qb->expr()->orX(
943
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
944
+                    $qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
945
+                )
946
+            );
947
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_GROUP) {
948
+            /*
949 949
 			 * Delete all group shares that are owned by this user
950 950
 			 * Or special user group shares that are received by this user
951 951
 			 */
952
-			$qb->where(
953
-				$qb->expr()->andX(
954
-					$qb->expr()->orX(
955
-						$qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)),
956
-						$qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))
957
-					),
958
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))
959
-				)
960
-			);
961
-
962
-			$qb->orWhere(
963
-				$qb->expr()->andX(
964
-					$qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)),
965
-					$qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
966
-				)
967
-			);
968
-		} else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
969
-			/*
952
+            $qb->where(
953
+                $qb->expr()->andX(
954
+                    $qb->expr()->orX(
955
+                        $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)),
956
+                        $qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP))
957
+                    ),
958
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))
959
+                )
960
+            );
961
+
962
+            $qb->orWhere(
963
+                $qb->expr()->andX(
964
+                    $qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)),
965
+                    $qb->expr()->eq('share_with', $qb->createNamedParameter($uid))
966
+                )
967
+            );
968
+        } else if ($shareType === \OCP\Share::SHARE_TYPE_LINK) {
969
+            /*
970 970
 			 * Delete all link shares owned by this user.
971 971
 			 * And all link shares initiated by this user (until #22327 is in)
972 972
 			 */
973
-			$qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)));
974
-
975
-			$qb->andWhere(
976
-				$qb->expr()->orX(
977
-					$qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
978
-					$qb->expr()->eq('uid_initiator', $qb->createNamedParameter($uid))
979
-				)
980
-			);
981
-		}
982
-
983
-		$qb->execute();
984
-	}
985
-
986
-	/**
987
-	 * Delete all shares received by this group. As well as any custom group
988
-	 * shares for group members.
989
-	 *
990
-	 * @param string $gid
991
-	 */
992
-	public function groupDeleted($gid) {
993
-		/*
973
+            $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_LINK)));
974
+
975
+            $qb->andWhere(
976
+                $qb->expr()->orX(
977
+                    $qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid)),
978
+                    $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($uid))
979
+                )
980
+            );
981
+        }
982
+
983
+        $qb->execute();
984
+    }
985
+
986
+    /**
987
+     * Delete all shares received by this group. As well as any custom group
988
+     * shares for group members.
989
+     *
990
+     * @param string $gid
991
+     */
992
+    public function groupDeleted($gid) {
993
+        /*
994 994
 		 * First delete all custom group shares for group members
995 995
 		 */
996
-		$qb = $this->dbConn->getQueryBuilder();
997
-		$qb->select('id')
998
-			->from('share')
999
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
1000
-			->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($gid)));
1001
-
1002
-		$cursor = $qb->execute();
1003
-		$ids = [];
1004
-		while($row = $cursor->fetch()) {
1005
-			$ids[] = (int)$row['id'];
1006
-		}
1007
-		$cursor->closeCursor();
1008
-
1009
-		if (!empty($ids)) {
1010
-			$chunks = array_chunk($ids, 100);
1011
-			foreach ($chunks as $chunk) {
1012
-				$qb->delete('share')
1013
-					->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
1014
-					->andWhere($qb->expr()->in('parent', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY)));
1015
-				$qb->execute();
1016
-			}
1017
-		}
1018
-
1019
-		/*
996
+        $qb = $this->dbConn->getQueryBuilder();
997
+        $qb->select('id')
998
+            ->from('share')
999
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
1000
+            ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($gid)));
1001
+
1002
+        $cursor = $qb->execute();
1003
+        $ids = [];
1004
+        while($row = $cursor->fetch()) {
1005
+            $ids[] = (int)$row['id'];
1006
+        }
1007
+        $cursor->closeCursor();
1008
+
1009
+        if (!empty($ids)) {
1010
+            $chunks = array_chunk($ids, 100);
1011
+            foreach ($chunks as $chunk) {
1012
+                $qb->delete('share')
1013
+                    ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
1014
+                    ->andWhere($qb->expr()->in('parent', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY)));
1015
+                $qb->execute();
1016
+            }
1017
+        }
1018
+
1019
+        /*
1020 1020
 		 * Now delete all the group shares
1021 1021
 		 */
1022
-		$qb = $this->dbConn->getQueryBuilder();
1023
-		$qb->delete('share')
1024
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
1025
-			->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($gid)));
1026
-		$qb->execute();
1027
-	}
1028
-
1029
-	/**
1030
-	 * Delete custom group shares to this group for this user
1031
-	 *
1032
-	 * @param string $uid
1033
-	 * @param string $gid
1034
-	 */
1035
-	public function userDeletedFromGroup($uid, $gid) {
1036
-		/*
1022
+        $qb = $this->dbConn->getQueryBuilder();
1023
+        $qb->delete('share')
1024
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
1025
+            ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($gid)));
1026
+        $qb->execute();
1027
+    }
1028
+
1029
+    /**
1030
+     * Delete custom group shares to this group for this user
1031
+     *
1032
+     * @param string $uid
1033
+     * @param string $gid
1034
+     */
1035
+    public function userDeletedFromGroup($uid, $gid) {
1036
+        /*
1037 1037
 		 * Get all group shares
1038 1038
 		 */
1039
-		$qb = $this->dbConn->getQueryBuilder();
1040
-		$qb->select('id')
1041
-			->from('share')
1042
-			->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
1043
-			->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($gid)));
1044
-
1045
-		$cursor = $qb->execute();
1046
-		$ids = [];
1047
-		while($row = $cursor->fetch()) {
1048
-			$ids[] = (int)$row['id'];
1049
-		}
1050
-		$cursor->closeCursor();
1051
-
1052
-		if (!empty($ids)) {
1053
-			$chunks = array_chunk($ids, 100);
1054
-			foreach ($chunks as $chunk) {
1055
-				/*
1039
+        $qb = $this->dbConn->getQueryBuilder();
1040
+        $qb->select('id')
1041
+            ->from('share')
1042
+            ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_GROUP)))
1043
+            ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($gid)));
1044
+
1045
+        $cursor = $qb->execute();
1046
+        $ids = [];
1047
+        while($row = $cursor->fetch()) {
1048
+            $ids[] = (int)$row['id'];
1049
+        }
1050
+        $cursor->closeCursor();
1051
+
1052
+        if (!empty($ids)) {
1053
+            $chunks = array_chunk($ids, 100);
1054
+            foreach ($chunks as $chunk) {
1055
+                /*
1056 1056
 				 * Delete all special shares wit this users for the found group shares
1057 1057
 				 */
1058
-				$qb->delete('share')
1059
-					->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
1060
-					->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($uid)))
1061
-					->andWhere($qb->expr()->in('parent', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY)));
1062
-				$qb->execute();
1063
-			}
1064
-		}
1065
-	}
1058
+                $qb->delete('share')
1059
+                    ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE_USERGROUP)))
1060
+                    ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($uid)))
1061
+                    ->andWhere($qb->expr()->in('parent', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY)));
1062
+                $qb->execute();
1063
+            }
1064
+        }
1065
+    }
1066 1066
 }
Please login to merge, or discard this patch.
lib/private/Repair/Collation.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -90,7 +90,7 @@
 block discarded – undo
90 90
 	}
91 91
 
92 92
 	/**
93
-	 * @param \Doctrine\DBAL\Connection $connection
93
+	 * @param IDBConnection $connection
94 94
 	 * @return string[]
95 95
 	 */
96 96
 	protected function getAllNonUTF8BinTables($connection) {
Please login to merge, or discard this patch.
Indentation   +79 added lines, -79 removed lines patch added patch discarded remove patch
@@ -33,94 +33,94 @@
 block discarded – undo
33 33
 use OCP\Migration\IRepairStep;
34 34
 
35 35
 class Collation implements IRepairStep {
36
-	/**  @var IConfig */
37
-	protected $config;
36
+    /**  @var IConfig */
37
+    protected $config;
38 38
 
39
-	/** @var ILogger */
40
-	protected $logger;
39
+    /** @var ILogger */
40
+    protected $logger;
41 41
 
42
-	/** @var IDBConnection */
43
-	protected $connection;
42
+    /** @var IDBConnection */
43
+    protected $connection;
44 44
 
45
-	/** @var bool */
46
-	protected $ignoreFailures;
45
+    /** @var bool */
46
+    protected $ignoreFailures;
47 47
 
48
-	/**
49
-	 * @param IConfig $config
50
-	 * @param ILogger $logger
51
-	 * @param IDBConnection $connection
52
-	 * @param bool $ignoreFailures
53
-	 */
54
-	public function __construct(IConfig $config, ILogger $logger, IDBConnection $connection, $ignoreFailures) {
55
-		$this->connection = $connection;
56
-		$this->config = $config;
57
-		$this->logger = $logger;
58
-		$this->ignoreFailures = $ignoreFailures;
59
-	}
48
+    /**
49
+     * @param IConfig $config
50
+     * @param ILogger $logger
51
+     * @param IDBConnection $connection
52
+     * @param bool $ignoreFailures
53
+     */
54
+    public function __construct(IConfig $config, ILogger $logger, IDBConnection $connection, $ignoreFailures) {
55
+        $this->connection = $connection;
56
+        $this->config = $config;
57
+        $this->logger = $logger;
58
+        $this->ignoreFailures = $ignoreFailures;
59
+    }
60 60
 
61
-	public function getName() {
62
-		return 'Repair MySQL collation';
63
-	}
61
+    public function getName() {
62
+        return 'Repair MySQL collation';
63
+    }
64 64
 
65
-	/**
66
-	 * Fix mime types
67
-	 */
68
-	public function run(IOutput $output) {
69
-		if (!$this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
70
-			$output->info('Not a mysql database -> nothing to no');
71
-			return;
72
-		}
65
+    /**
66
+     * Fix mime types
67
+     */
68
+    public function run(IOutput $output) {
69
+        if (!$this->connection->getDatabasePlatform() instanceof MySqlPlatform) {
70
+            $output->info('Not a mysql database -> nothing to no');
71
+            return;
72
+        }
73 73
 
74
-		$characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
74
+        $characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
75 75
 
76
-		$tables = $this->getAllNonUTF8BinTables($this->connection);
77
-		foreach ($tables as $table) {
78
-			$output->info("Change row format for $table ...");
79
-			$query = $this->connection->prepare('ALTER TABLE `' . $table . '` ROW_FORMAT = DYNAMIC;');
80
-			try {
81
-				$query->execute();
82
-			} catch (DriverException $e) {
83
-				// Just log this
84
-				$this->logger->logException($e);
85
-				if (!$this->ignoreFailures) {
86
-					throw $e;
87
-				}
88
-			}
76
+        $tables = $this->getAllNonUTF8BinTables($this->connection);
77
+        foreach ($tables as $table) {
78
+            $output->info("Change row format for $table ...");
79
+            $query = $this->connection->prepare('ALTER TABLE `' . $table . '` ROW_FORMAT = DYNAMIC;');
80
+            try {
81
+                $query->execute();
82
+            } catch (DriverException $e) {
83
+                // Just log this
84
+                $this->logger->logException($e);
85
+                if (!$this->ignoreFailures) {
86
+                    throw $e;
87
+                }
88
+            }
89 89
 
90
-			$output->info("Change collation for $table ...");
91
-			$query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET ' . $characterSet . ' COLLATE ' . $characterSet . '_bin;');
92
-			try {
93
-				$query->execute();
94
-			} catch (DriverException $e) {
95
-				// Just log this
96
-				$this->logger->logException($e);
97
-				if (!$this->ignoreFailures) {
98
-					throw $e;
99
-				}
100
-			}
101
-		}
102
-	}
90
+            $output->info("Change collation for $table ...");
91
+            $query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET ' . $characterSet . ' COLLATE ' . $characterSet . '_bin;');
92
+            try {
93
+                $query->execute();
94
+            } catch (DriverException $e) {
95
+                // Just log this
96
+                $this->logger->logException($e);
97
+                if (!$this->ignoreFailures) {
98
+                    throw $e;
99
+                }
100
+            }
101
+        }
102
+    }
103 103
 
104
-	/**
105
-	 * @param \Doctrine\DBAL\Connection $connection
106
-	 * @return string[]
107
-	 */
108
-	protected function getAllNonUTF8BinTables($connection) {
109
-		$dbName = $this->config->getSystemValue("dbname");
110
-		$characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
111
-		$rows = $connection->fetchAll(
112
-			"SELECT DISTINCT(TABLE_NAME) AS `table`" .
113
-			"	FROM INFORMATION_SCHEMA . COLUMNS" .
114
-			"	WHERE TABLE_SCHEMA = ?" .
115
-			"	AND (COLLATION_NAME <> '" . $characterSet . "_bin' OR CHARACTER_SET_NAME <> '" . $characterSet . "')" .
116
-			"	AND TABLE_NAME LIKE \"*PREFIX*%\"",
117
-			array($dbName)
118
-		);
119
-		$result = array();
120
-		foreach ($rows as $row) {
121
-			$result[] = $row['table'];
122
-		}
123
-		return $result;
124
-	}
104
+    /**
105
+     * @param \Doctrine\DBAL\Connection $connection
106
+     * @return string[]
107
+     */
108
+    protected function getAllNonUTF8BinTables($connection) {
109
+        $dbName = $this->config->getSystemValue("dbname");
110
+        $characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
111
+        $rows = $connection->fetchAll(
112
+            "SELECT DISTINCT(TABLE_NAME) AS `table`" .
113
+            "	FROM INFORMATION_SCHEMA . COLUMNS" .
114
+            "	WHERE TABLE_SCHEMA = ?" .
115
+            "	AND (COLLATION_NAME <> '" . $characterSet . "_bin' OR CHARACTER_SET_NAME <> '" . $characterSet . "')" .
116
+            "	AND TABLE_NAME LIKE \"*PREFIX*%\"",
117
+            array($dbName)
118
+        );
119
+        $result = array();
120
+        foreach ($rows as $row) {
121
+            $result[] = $row['table'];
122
+        }
123
+        return $result;
124
+    }
125 125
 }
126 126
 
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -76,7 +76,7 @@  discard block
 block discarded – undo
76 76
 		$tables = $this->getAllNonUTF8BinTables($this->connection);
77 77
 		foreach ($tables as $table) {
78 78
 			$output->info("Change row format for $table ...");
79
-			$query = $this->connection->prepare('ALTER TABLE `' . $table . '` ROW_FORMAT = DYNAMIC;');
79
+			$query = $this->connection->prepare('ALTER TABLE `'.$table.'` ROW_FORMAT = DYNAMIC;');
80 80
 			try {
81 81
 				$query->execute();
82 82
 			} catch (DriverException $e) {
@@ -88,7 +88,7 @@  discard block
 block discarded – undo
88 88
 			}
89 89
 
90 90
 			$output->info("Change collation for $table ...");
91
-			$query = $this->connection->prepare('ALTER TABLE `' . $table . '` CONVERT TO CHARACTER SET ' . $characterSet . ' COLLATE ' . $characterSet . '_bin;');
91
+			$query = $this->connection->prepare('ALTER TABLE `'.$table.'` CONVERT TO CHARACTER SET '.$characterSet.' COLLATE '.$characterSet.'_bin;');
92 92
 			try {
93 93
 				$query->execute();
94 94
 			} catch (DriverException $e) {
@@ -109,10 +109,10 @@  discard block
 block discarded – undo
109 109
 		$dbName = $this->config->getSystemValue("dbname");
110 110
 		$characterSet = $this->config->getSystemValue('mysql.utf8mb4', false) ? 'utf8mb4' : 'utf8';
111 111
 		$rows = $connection->fetchAll(
112
-			"SELECT DISTINCT(TABLE_NAME) AS `table`" .
113
-			"	FROM INFORMATION_SCHEMA . COLUMNS" .
114
-			"	WHERE TABLE_SCHEMA = ?" .
115
-			"	AND (COLLATION_NAME <> '" . $characterSet . "_bin' OR CHARACTER_SET_NAME <> '" . $characterSet . "')" .
112
+			"SELECT DISTINCT(TABLE_NAME) AS `table`".
113
+			"	FROM INFORMATION_SCHEMA . COLUMNS".
114
+			"	WHERE TABLE_SCHEMA = ?".
115
+			"	AND (COLLATION_NAME <> '".$characterSet."_bin' OR CHARACTER_SET_NAME <> '".$characterSet."')".
116 116
 			"	AND TABLE_NAME LIKE \"*PREFIX*%\"",
117 117
 			array($dbName)
118 118
 		);
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/ShareTypeList.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -61,7 +61,7 @@
 block discarded – undo
61 61
 	 * The deserialize method is called during xml parsing.
62 62
 	 *
63 63
 	 * @param Reader $reader
64
-	 * @return mixed
64
+	 * @return null|ShareTypeList
65 65
 	 */
66 66
 	static function xmlDeserialize(Reader $reader) {
67 67
 		$shareTypes = [];
Please login to merge, or discard this patch.
Indentation   +51 added lines, -51 removed lines patch added patch discarded remove patch
@@ -32,61 +32,61 @@
 block discarded – undo
32 32
  * This property contains multiple "share-type" elements, each containing a share type.
33 33
  */
34 34
 class ShareTypeList implements Element {
35
-	const NS_OWNCLOUD = 'http://owncloud.org/ns';
35
+    const NS_OWNCLOUD = 'http://owncloud.org/ns';
36 36
 
37
-	/**
38
-	 * Share types
39
-	 *
40
-	 * @var int[]
41
-	 */
42
-	private $shareTypes;
37
+    /**
38
+     * Share types
39
+     *
40
+     * @var int[]
41
+     */
42
+    private $shareTypes;
43 43
 
44
-	/**
45
-	 * @param int[] $shareTypes
46
-	 */
47
-	public function __construct($shareTypes) {
48
-		$this->shareTypes = $shareTypes;
49
-	}
44
+    /**
45
+     * @param int[] $shareTypes
46
+     */
47
+    public function __construct($shareTypes) {
48
+        $this->shareTypes = $shareTypes;
49
+    }
50 50
 
51
-	/**
52
-	 * Returns the share types
53
-	 *
54
-	 * @return int[]
55
-	 */
56
-	public function getShareTypes() {
57
-		return $this->shareTypes;
58
-	}
51
+    /**
52
+     * Returns the share types
53
+     *
54
+     * @return int[]
55
+     */
56
+    public function getShareTypes() {
57
+        return $this->shareTypes;
58
+    }
59 59
 
60
-	/**
61
-	 * The deserialize method is called during xml parsing.
62
-	 *
63
-	 * @param Reader $reader
64
-	 * @return mixed
65
-	 */
66
-	static function xmlDeserialize(Reader $reader) {
67
-		$shareTypes = [];
60
+    /**
61
+     * The deserialize method is called during xml parsing.
62
+     *
63
+     * @param Reader $reader
64
+     * @return mixed
65
+     */
66
+    static function xmlDeserialize(Reader $reader) {
67
+        $shareTypes = [];
68 68
 
69
-		$tree = $reader->parseInnerTree();
70
-		if ($tree === null) {
71
-			return null;
72
-		}
73
-		foreach ($tree as $elem) {
74
-			if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}share-type') {
75
-				$shareTypes[] = (int)$elem['value'];
76
-			}
77
-		}
78
-		return new self($shareTypes);
79
-	}
69
+        $tree = $reader->parseInnerTree();
70
+        if ($tree === null) {
71
+            return null;
72
+        }
73
+        foreach ($tree as $elem) {
74
+            if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}share-type') {
75
+                $shareTypes[] = (int)$elem['value'];
76
+            }
77
+        }
78
+        return new self($shareTypes);
79
+    }
80 80
 
81
-	/**
82
-	 * The xmlSerialize metod is called during xml writing.
83
-	 *
84
-	 * @param Writer $writer
85
-	 * @return void
86
-	 */
87
-	function xmlSerialize(Writer $writer) {
88
-		foreach ($this->shareTypes as $shareType) {
89
-			$writer->writeElement('{' . self::NS_OWNCLOUD . '}share-type', $shareType);
90
-		}
91
-	}
81
+    /**
82
+     * The xmlSerialize metod is called during xml writing.
83
+     *
84
+     * @param Writer $writer
85
+     * @return void
86
+     */
87
+    function xmlSerialize(Writer $writer) {
88
+        foreach ($this->shareTypes as $shareType) {
89
+            $writer->writeElement('{' . self::NS_OWNCLOUD . '}share-type', $shareType);
90
+        }
91
+    }
92 92
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -71,8 +71,8 @@  discard block
 block discarded – undo
71 71
 			return null;
72 72
 		}
73 73
 		foreach ($tree as $elem) {
74
-			if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}share-type') {
75
-				$shareTypes[] = (int)$elem['value'];
74
+			if ($elem['name'] === '{'.self::NS_OWNCLOUD.'}share-type') {
75
+				$shareTypes[] = (int) $elem['value'];
76 76
 			}
77 77
 		}
78 78
 		return new self($shareTypes);
@@ -86,7 +86,7 @@  discard block
 block discarded – undo
86 86
 	 */
87 87
 	function xmlSerialize(Writer $writer) {
88 88
 		foreach ($this->shareTypes as $shareType) {
89
-			$writer->writeElement('{' . self::NS_OWNCLOUD . '}share-type', $shareType);
89
+			$writer->writeElement('{'.self::NS_OWNCLOUD.'}share-type', $shareType);
90 90
 		}
91 91
 	}
92 92
 }
Please login to merge, or discard this patch.
apps/dav/lib/Connector/Sabre/TagList.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -80,7 +80,7 @@
 block discarded – undo
80 80
 	 * the next element.
81 81
 	 *
82 82
 	 * @param Reader $reader
83
-	 * @return mixed
83
+	 * @return null|TagList
84 84
 	 */
85 85
 	static function xmlDeserialize(Reader $reader) {
86 86
 		$tags = [];
Please login to merge, or discard this patch.
Indentation   +79 added lines, -79 removed lines patch added patch discarded remove patch
@@ -34,92 +34,92 @@
 block discarded – undo
34 34
  * This property contains multiple "tag" elements, each containing a tag name.
35 35
  */
36 36
 class TagList implements Element {
37
-	const NS_OWNCLOUD = 'http://owncloud.org/ns';
37
+    const NS_OWNCLOUD = 'http://owncloud.org/ns';
38 38
 
39
-	/**
40
-	 * tags
41
-	 *
42
-	 * @var array
43
-	 */
44
-	private $tags;
39
+    /**
40
+     * tags
41
+     *
42
+     * @var array
43
+     */
44
+    private $tags;
45 45
 
46
-	/**
47
-	 * @param array $tags
48
-	 */
49
-	public function __construct(array $tags) {
50
-		$this->tags = $tags;
51
-	}
46
+    /**
47
+     * @param array $tags
48
+     */
49
+    public function __construct(array $tags) {
50
+        $this->tags = $tags;
51
+    }
52 52
 
53
-	/**
54
-	 * Returns the tags
55
-	 *
56
-	 * @return array
57
-	 */
58
-	public function getTags() {
53
+    /**
54
+     * Returns the tags
55
+     *
56
+     * @return array
57
+     */
58
+    public function getTags() {
59 59
 
60
-		return $this->tags;
60
+        return $this->tags;
61 61
 
62
-	}
62
+    }
63 63
 
64
-	/**
65
-	 * The deserialize method is called during xml parsing.
66
-	 *
67
-	 * This method is called statictly, this is because in theory this method
68
-	 * may be used as a type of constructor, or factory method.
69
-	 *
70
-	 * Often you want to return an instance of the current class, but you are
71
-	 * free to return other data as well.
72
-	 *
73
-	 * You are responsible for advancing the reader to the next element. Not
74
-	 * doing anything will result in a never-ending loop.
75
-	 *
76
-	 * If you just want to skip parsing for this element altogether, you can
77
-	 * just call $reader->next();
78
-	 *
79
-	 * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
80
-	 * the next element.
81
-	 *
82
-	 * @param Reader $reader
83
-	 * @return mixed
84
-	 */
85
-	static function xmlDeserialize(Reader $reader) {
86
-		$tags = [];
64
+    /**
65
+     * The deserialize method is called during xml parsing.
66
+     *
67
+     * This method is called statictly, this is because in theory this method
68
+     * may be used as a type of constructor, or factory method.
69
+     *
70
+     * Often you want to return an instance of the current class, but you are
71
+     * free to return other data as well.
72
+     *
73
+     * You are responsible for advancing the reader to the next element. Not
74
+     * doing anything will result in a never-ending loop.
75
+     *
76
+     * If you just want to skip parsing for this element altogether, you can
77
+     * just call $reader->next();
78
+     *
79
+     * $reader->parseInnerTree() will parse the entire sub-tree, and advance to
80
+     * the next element.
81
+     *
82
+     * @param Reader $reader
83
+     * @return mixed
84
+     */
85
+    static function xmlDeserialize(Reader $reader) {
86
+        $tags = [];
87 87
 
88
-		$tree = $reader->parseInnerTree();
89
-		if ($tree === null) {
90
-			return null;
91
-		}
92
-		foreach ($tree as $elem) {
93
-			if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}tag') {
94
-				$tags[] = $elem['value'];
95
-			}
96
-		}
97
-		return new self($tags);
98
-	}
88
+        $tree = $reader->parseInnerTree();
89
+        if ($tree === null) {
90
+            return null;
91
+        }
92
+        foreach ($tree as $elem) {
93
+            if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}tag') {
94
+                $tags[] = $elem['value'];
95
+            }
96
+        }
97
+        return new self($tags);
98
+    }
99 99
 
100
-	/**
101
-	 * The xmlSerialize metod is called during xml writing.
102
-	 *
103
-	 * Use the $writer argument to write its own xml serialization.
104
-	 *
105
-	 * An important note: do _not_ create a parent element. Any element
106
-	 * implementing XmlSerializble should only ever write what's considered
107
-	 * its 'inner xml'.
108
-	 *
109
-	 * The parent of the current element is responsible for writing a
110
-	 * containing element.
111
-	 *
112
-	 * This allows serializers to be re-used for different element names.
113
-	 *
114
-	 * If you are opening new elements, you must also close them again.
115
-	 *
116
-	 * @param Writer $writer
117
-	 * @return void
118
-	 */
119
-	function xmlSerialize(Writer $writer) {
100
+    /**
101
+     * The xmlSerialize metod is called during xml writing.
102
+     *
103
+     * Use the $writer argument to write its own xml serialization.
104
+     *
105
+     * An important note: do _not_ create a parent element. Any element
106
+     * implementing XmlSerializble should only ever write what's considered
107
+     * its 'inner xml'.
108
+     *
109
+     * The parent of the current element is responsible for writing a
110
+     * containing element.
111
+     *
112
+     * This allows serializers to be re-used for different element names.
113
+     *
114
+     * If you are opening new elements, you must also close them again.
115
+     *
116
+     * @param Writer $writer
117
+     * @return void
118
+     */
119
+    function xmlSerialize(Writer $writer) {
120 120
 
121
-		foreach ($this->tags as $tag) {
122
-			$writer->writeElement('{' . self::NS_OWNCLOUD . '}tag', $tag);
123
-		}
124
-	}
121
+        foreach ($this->tags as $tag) {
122
+            $writer->writeElement('{' . self::NS_OWNCLOUD . '}tag', $tag);
123
+        }
124
+    }
125 125
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -90,7 +90,7 @@  discard block
 block discarded – undo
90 90
 			return null;
91 91
 		}
92 92
 		foreach ($tree as $elem) {
93
-			if ($elem['name'] === '{' . self::NS_OWNCLOUD . '}tag') {
93
+			if ($elem['name'] === '{'.self::NS_OWNCLOUD.'}tag') {
94 94
 				$tags[] = $elem['value'];
95 95
 			}
96 96
 		}
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
 	function xmlSerialize(Writer $writer) {
120 120
 
121 121
 		foreach ($this->tags as $tag) {
122
-			$writer->writeElement('{' . self::NS_OWNCLOUD . '}tag', $tag);
122
+			$writer->writeElement('{'.self::NS_OWNCLOUD.'}tag', $tag);
123 123
 		}
124 124
 	}
125 125
 }
Please login to merge, or discard this patch.
lib/private/Share/MailNotifications.php 3 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -30,7 +30,6 @@
 block discarded – undo
30 30
 
31 31
 namespace OC\Share;
32 32
 
33
-use DateTime;
34 33
 use OCP\IL10N;
35 34
 use OCP\IURLGenerator;
36 35
 use OCP\IUser;
Please login to merge, or discard this patch.
Indentation   +100 added lines, -100 removed lines patch added patch discarded remove patch
@@ -46,113 +46,113 @@
 block discarded – undo
46 46
  */
47 47
 class MailNotifications {
48 48
 
49
-	/** @var IUser sender userId */
50
-	private $user;
51
-	/** @var string sender email address */
52
-	private $replyTo;
53
-	/** @var string */
54
-	private $senderDisplayName;
55
-	/** @var IL10N */
56
-	private $l;
57
-	/** @var IMailer */
58
-	private $mailer;
59
-	/** @var Defaults */
60
-	private $defaults;
61
-	/** @var ILogger */
62
-	private $logger;
63
-	/** @var IURLGenerator */
64
-	private $urlGenerator;
49
+    /** @var IUser sender userId */
50
+    private $user;
51
+    /** @var string sender email address */
52
+    private $replyTo;
53
+    /** @var string */
54
+    private $senderDisplayName;
55
+    /** @var IL10N */
56
+    private $l;
57
+    /** @var IMailer */
58
+    private $mailer;
59
+    /** @var Defaults */
60
+    private $defaults;
61
+    /** @var ILogger */
62
+    private $logger;
63
+    /** @var IURLGenerator */
64
+    private $urlGenerator;
65 65
 
66
-	/**
67
-	 * @param IUser $user
68
-	 * @param IL10N $l10n
69
-	 * @param IMailer $mailer
70
-	 * @param ILogger $logger
71
-	 * @param Defaults $defaults
72
-	 * @param IURLGenerator $urlGenerator
73
-	 */
74
-	public function __construct(IUser $user,
75
-								IL10N $l10n,
76
-								IMailer $mailer,
77
-								ILogger $logger,
78
-								Defaults $defaults,
79
-								IURLGenerator $urlGenerator) {
80
-		$this->l = $l10n;
81
-		$this->user = $user;
82
-		$this->mailer = $mailer;
83
-		$this->logger = $logger;
84
-		$this->defaults = $defaults;
85
-		$this->urlGenerator = $urlGenerator;
66
+    /**
67
+     * @param IUser $user
68
+     * @param IL10N $l10n
69
+     * @param IMailer $mailer
70
+     * @param ILogger $logger
71
+     * @param Defaults $defaults
72
+     * @param IURLGenerator $urlGenerator
73
+     */
74
+    public function __construct(IUser $user,
75
+                                IL10N $l10n,
76
+                                IMailer $mailer,
77
+                                ILogger $logger,
78
+                                Defaults $defaults,
79
+                                IURLGenerator $urlGenerator) {
80
+        $this->l = $l10n;
81
+        $this->user = $user;
82
+        $this->mailer = $mailer;
83
+        $this->logger = $logger;
84
+        $this->defaults = $defaults;
85
+        $this->urlGenerator = $urlGenerator;
86 86
 
87
-		$this->replyTo = $this->user->getEMailAddress();
88
-		$this->senderDisplayName = $this->user->getDisplayName();
89
-	}
87
+        $this->replyTo = $this->user->getEMailAddress();
88
+        $this->senderDisplayName = $this->user->getDisplayName();
89
+    }
90 90
 
91
-	/**
92
-	 * inform recipient about public link share
93
-	 *
94
-	 * @param string $recipient recipient email address
95
-	 * @param string $filename the shared file
96
-	 * @param string $link the public link
97
-	 * @param int $expiration expiration date (timestamp)
98
-	 * @return string[] $result of failed recipients
99
-	 */
100
-	public function sendLinkShareMail($recipient, $filename, $link, $expiration) {
101
-		$subject = (string)$this->l->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]);
102
-		list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration);
91
+    /**
92
+     * inform recipient about public link share
93
+     *
94
+     * @param string $recipient recipient email address
95
+     * @param string $filename the shared file
96
+     * @param string $link the public link
97
+     * @param int $expiration expiration date (timestamp)
98
+     * @return string[] $result of failed recipients
99
+     */
100
+    public function sendLinkShareMail($recipient, $filename, $link, $expiration) {
101
+        $subject = (string)$this->l->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]);
102
+        list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration);
103 103
 
104
-		$recipient = str_replace([', ', '; ', ',', ';', ' '], ',', $recipient);
105
-		$recipients = explode(',', $recipient);
106
-		try {
107
-			$message = $this->mailer->createMessage();
108
-			$message->setSubject($subject);
109
-			$message->setTo($recipients);
110
-			$message->setHtmlBody($htmlBody);
111
-			$message->setPlainBody($textBody);
112
-			$message->setFrom([
113
-				Util::getDefaultEmailAddress('sharing-noreply') =>
114
-					(string)$this->l->t('%s via %s', [
115
-						$this->senderDisplayName,
116
-						$this->defaults->getName()
117
-					]),
118
-			]);
119
-			if(!is_null($this->replyTo)) {
120
-				$message->setReplyTo([$this->replyTo]);
121
-			}
104
+        $recipient = str_replace([', ', '; ', ',', ';', ' '], ',', $recipient);
105
+        $recipients = explode(',', $recipient);
106
+        try {
107
+            $message = $this->mailer->createMessage();
108
+            $message->setSubject($subject);
109
+            $message->setTo($recipients);
110
+            $message->setHtmlBody($htmlBody);
111
+            $message->setPlainBody($textBody);
112
+            $message->setFrom([
113
+                Util::getDefaultEmailAddress('sharing-noreply') =>
114
+                    (string)$this->l->t('%s via %s', [
115
+                        $this->senderDisplayName,
116
+                        $this->defaults->getName()
117
+                    ]),
118
+            ]);
119
+            if(!is_null($this->replyTo)) {
120
+                $message->setReplyTo([$this->replyTo]);
121
+            }
122 122
 
123
-			return $this->mailer->send($message);
124
-		} catch (\Exception $e) {
125
-			$this->logger->error("Can't send mail with public link to $recipient: ".$e->getMessage(), ['app' => 'sharing']);
126
-			return [$recipient];
127
-		}
128
-	}
123
+            return $this->mailer->send($message);
124
+        } catch (\Exception $e) {
125
+            $this->logger->error("Can't send mail with public link to $recipient: ".$e->getMessage(), ['app' => 'sharing']);
126
+            return [$recipient];
127
+        }
128
+    }
129 129
 
130
-	/**
131
-	 * create mail body for plain text and html mail
132
-	 *
133
-	 * @param string $filename the shared file
134
-	 * @param string $link link to the shared file
135
-	 * @param int $expiration expiration date (timestamp)
136
-	 * @param string $prefix prefix of mail template files
137
-	 * @return array an array of the html mail body and the plain text mail body
138
-	 */
139
-	private function createMailBody($filename, $link, $expiration, $prefix = '') {
140
-		$formattedDate = $expiration ? $this->l->l('date', $expiration) : null;
130
+    /**
131
+     * create mail body for plain text and html mail
132
+     *
133
+     * @param string $filename the shared file
134
+     * @param string $link link to the shared file
135
+     * @param int $expiration expiration date (timestamp)
136
+     * @param string $prefix prefix of mail template files
137
+     * @return array an array of the html mail body and the plain text mail body
138
+     */
139
+    private function createMailBody($filename, $link, $expiration, $prefix = '') {
140
+        $formattedDate = $expiration ? $this->l->l('date', $expiration) : null;
141 141
 
142
-		$html = new \OC_Template('core', $prefix . 'mail', '');
143
-		$html->assign ('link', $link);
144
-		$html->assign ('user_displayname', $this->senderDisplayName);
145
-		$html->assign ('filename', $filename);
146
-		$html->assign('expiration',  $formattedDate);
147
-		$htmlMail = $html->fetchPage();
142
+        $html = new \OC_Template('core', $prefix . 'mail', '');
143
+        $html->assign ('link', $link);
144
+        $html->assign ('user_displayname', $this->senderDisplayName);
145
+        $html->assign ('filename', $filename);
146
+        $html->assign('expiration',  $formattedDate);
147
+        $htmlMail = $html->fetchPage();
148 148
 
149
-		$plainText = new \OC_Template('core', $prefix . 'altmail', '');
150
-		$plainText->assign ('link', $link);
151
-		$plainText->assign ('user_displayname', $this->senderDisplayName);
152
-		$plainText->assign ('filename', $filename);
153
-		$plainText->assign('expiration', $formattedDate);
154
-		$plainTextMail = $plainText->fetchPage();
149
+        $plainText = new \OC_Template('core', $prefix . 'altmail', '');
150
+        $plainText->assign ('link', $link);
151
+        $plainText->assign ('user_displayname', $this->senderDisplayName);
152
+        $plainText->assign ('filename', $filename);
153
+        $plainText->assign('expiration', $formattedDate);
154
+        $plainTextMail = $plainText->fetchPage();
155 155
 
156
-		return [$htmlMail, $plainTextMail];
157
-	}
156
+        return [$htmlMail, $plainTextMail];
157
+    }
158 158
 }
Please login to merge, or discard this patch.
Spacing   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
 	 * @return string[] $result of failed recipients
99 99
 	 */
100 100
 	public function sendLinkShareMail($recipient, $filename, $link, $expiration) {
101
-		$subject = (string)$this->l->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]);
101
+		$subject = (string) $this->l->t('%s shared »%s« with you', [$this->senderDisplayName, $filename]);
102 102
 		list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration);
103 103
 
104 104
 		$recipient = str_replace([', ', '; ', ',', ';', ' '], ',', $recipient);
@@ -111,12 +111,12 @@  discard block
 block discarded – undo
111 111
 			$message->setPlainBody($textBody);
112 112
 			$message->setFrom([
113 113
 				Util::getDefaultEmailAddress('sharing-noreply') =>
114
-					(string)$this->l->t('%s via %s', [
114
+					(string) $this->l->t('%s via %s', [
115 115
 						$this->senderDisplayName,
116 116
 						$this->defaults->getName()
117 117
 					]),
118 118
 			]);
119
-			if(!is_null($this->replyTo)) {
119
+			if (!is_null($this->replyTo)) {
120 120
 				$message->setReplyTo([$this->replyTo]);
121 121
 			}
122 122
 
@@ -139,17 +139,17 @@  discard block
 block discarded – undo
139 139
 	private function createMailBody($filename, $link, $expiration, $prefix = '') {
140 140
 		$formattedDate = $expiration ? $this->l->l('date', $expiration) : null;
141 141
 
142
-		$html = new \OC_Template('core', $prefix . 'mail', '');
143
-		$html->assign ('link', $link);
144
-		$html->assign ('user_displayname', $this->senderDisplayName);
145
-		$html->assign ('filename', $filename);
146
-		$html->assign('expiration',  $formattedDate);
142
+		$html = new \OC_Template('core', $prefix.'mail', '');
143
+		$html->assign('link', $link);
144
+		$html->assign('user_displayname', $this->senderDisplayName);
145
+		$html->assign('filename', $filename);
146
+		$html->assign('expiration', $formattedDate);
147 147
 		$htmlMail = $html->fetchPage();
148 148
 
149
-		$plainText = new \OC_Template('core', $prefix . 'altmail', '');
150
-		$plainText->assign ('link', $link);
151
-		$plainText->assign ('user_displayname', $this->senderDisplayName);
152
-		$plainText->assign ('filename', $filename);
149
+		$plainText = new \OC_Template('core', $prefix.'altmail', '');
150
+		$plainText->assign('link', $link);
151
+		$plainText->assign('user_displayname', $this->senderDisplayName);
152
+		$plainText->assign('filename', $filename);
153 153
 		$plainText->assign('expiration', $formattedDate);
154 154
 		$plainTextMail = $plainText->fetchPage();
155 155
 
Please login to merge, or discard this patch.
lib/private/legacy/app.php 4 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -51,7 +51,6 @@
 block discarded – undo
51 51
 use OC\App\InfoParser;
52 52
 use OC\App\Platform;
53 53
 use OC\Installer;
54
-use OC\OCSClient;
55 54
 use OC\Repair;
56 55
 use OCP\App\ManagerEvent;
57 56
 
Please login to merge, or discard this patch.
Doc Comments   +6 added lines, -1 removed lines patch added patch discarded remove patch
@@ -1063,7 +1063,7 @@  discard block
 block discarded – undo
1063 1063
 	 * @param string $app
1064 1064
 	 * @param \OCP\IConfig $config
1065 1065
 	 * @param \OCP\IL10N $l
1066
-	 * @return bool
1066
+	 * @return string
1067 1067
 	 *
1068 1068
 	 * @throws Exception if app is not compatible with this version of ownCloud
1069 1069
 	 * @throws Exception if no app-name was specified
@@ -1243,6 +1243,11 @@  discard block
 block discarded – undo
1243 1243
 		}
1244 1244
 	}
1245 1245
 
1246
+	/**
1247
+	 * @param string $lang
1248
+	 *
1249
+	 * @return string
1250
+	 */
1246 1251
 	protected static function findBestL10NOption($options, $lang) {
1247 1252
 		$fallback = $similarLangFallback = $englishFallback = false;
1248 1253
 
Please login to merge, or discard this patch.
Indentation   +1266 added lines, -1266 removed lines patch added patch discarded remove patch
@@ -61,1270 +61,1270 @@
 block discarded – undo
61 61
  * upgrading and removing apps.
62 62
  */
63 63
 class OC_App {
64
-	static private $appVersion = [];
65
-	static private $adminForms = array();
66
-	static private $personalForms = array();
67
-	static private $appInfo = array();
68
-	static private $appTypes = array();
69
-	static private $loadedApps = array();
70
-	static private $altLogin = array();
71
-	static private $alreadyRegistered = [];
72
-	const officialApp = 200;
73
-
74
-	/**
75
-	 * clean the appId
76
-	 *
77
-	 * @param string|boolean $app AppId that needs to be cleaned
78
-	 * @return string
79
-	 */
80
-	public static function cleanAppId($app) {
81
-		return str_replace(array('\0', '/', '\\', '..'), '', $app);
82
-	}
83
-
84
-	/**
85
-	 * Check if an app is loaded
86
-	 *
87
-	 * @param string $app
88
-	 * @return bool
89
-	 */
90
-	public static function isAppLoaded($app) {
91
-		return in_array($app, self::$loadedApps, true);
92
-	}
93
-
94
-	/**
95
-	 * loads all apps
96
-	 *
97
-	 * @param string[] | string | null $types
98
-	 * @return bool
99
-	 *
100
-	 * This function walks through the ownCloud directory and loads all apps
101
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
102
-	 * exists.
103
-	 *
104
-	 * if $types is set, only apps of those types will be loaded
105
-	 */
106
-	public static function loadApps($types = null) {
107
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
108
-			return false;
109
-		}
110
-		// Load the enabled apps here
111
-		$apps = self::getEnabledApps();
112
-
113
-		// Add each apps' folder as allowed class path
114
-		foreach($apps as $app) {
115
-			$path = self::getAppPath($app);
116
-			if($path !== false) {
117
-				self::registerAutoloading($app, $path);
118
-			}
119
-		}
120
-
121
-		// prevent app.php from printing output
122
-		ob_start();
123
-		foreach ($apps as $app) {
124
-			if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
125
-				self::loadApp($app);
126
-			}
127
-		}
128
-		ob_end_clean();
129
-
130
-		return true;
131
-	}
132
-
133
-	/**
134
-	 * load a single app
135
-	 *
136
-	 * @param string $app
137
-	 */
138
-	public static function loadApp($app) {
139
-		self::$loadedApps[] = $app;
140
-		$appPath = self::getAppPath($app);
141
-		if($appPath === false) {
142
-			return;
143
-		}
144
-
145
-		// in case someone calls loadApp() directly
146
-		self::registerAutoloading($app, $appPath);
147
-
148
-		if (is_file($appPath . '/appinfo/app.php')) {
149
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
150
-			self::requireAppFile($app);
151
-			if (self::isType($app, array('authentication'))) {
152
-				// since authentication apps affect the "is app enabled for group" check,
153
-				// the enabled apps cache needs to be cleared to make sure that the
154
-				// next time getEnableApps() is called it will also include apps that were
155
-				// enabled for groups
156
-				self::$enabledAppsCache = array();
157
-			}
158
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
159
-		}
160
-
161
-		$info = self::getAppInfo($app);
162
-		if (!empty($info['activity']['filters'])) {
163
-			foreach ($info['activity']['filters'] as $filter) {
164
-				\OC::$server->getActivityManager()->registerFilter($filter);
165
-			}
166
-		}
167
-		if (!empty($info['activity']['settings'])) {
168
-			foreach ($info['activity']['settings'] as $setting) {
169
-				\OC::$server->getActivityManager()->registerSetting($setting);
170
-			}
171
-		}
172
-		if (!empty($info['activity']['providers'])) {
173
-			foreach ($info['activity']['providers'] as $provider) {
174
-				\OC::$server->getActivityManager()->registerProvider($provider);
175
-			}
176
-		}
177
-	}
178
-
179
-	/**
180
-	 * @internal
181
-	 * @param string $app
182
-	 * @param string $path
183
-	 */
184
-	public static function registerAutoloading($app, $path) {
185
-		$key = $app . '-' . $path;
186
-		if(isset(self::$alreadyRegistered[$key])) {
187
-			return;
188
-		}
189
-		self::$alreadyRegistered[$key] = true;
190
-		// Register on PSR-4 composer autoloader
191
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
192
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
193
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
194
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
195
-		}
196
-
197
-		// Register on legacy autoloader
198
-		\OC::$loader->addValidRoot($path);
199
-	}
200
-
201
-	/**
202
-	 * Load app.php from the given app
203
-	 *
204
-	 * @param string $app app name
205
-	 */
206
-	private static function requireAppFile($app) {
207
-		try {
208
-			// encapsulated here to avoid variable scope conflicts
209
-			require_once $app . '/appinfo/app.php';
210
-		} catch (Error $ex) {
211
-			\OC::$server->getLogger()->logException($ex);
212
-			$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
213
-			if (!in_array($app, $blacklist)) {
214
-				self::disable($app);
215
-			}
216
-		}
217
-	}
218
-
219
-	/**
220
-	 * check if an app is of a specific type
221
-	 *
222
-	 * @param string $app
223
-	 * @param string|array $types
224
-	 * @return bool
225
-	 */
226
-	public static function isType($app, $types) {
227
-		if (is_string($types)) {
228
-			$types = array($types);
229
-		}
230
-		$appTypes = self::getAppTypes($app);
231
-		foreach ($types as $type) {
232
-			if (array_search($type, $appTypes) !== false) {
233
-				return true;
234
-			}
235
-		}
236
-		return false;
237
-	}
238
-
239
-	/**
240
-	 * get the types of an app
241
-	 *
242
-	 * @param string $app
243
-	 * @return array
244
-	 */
245
-	private static function getAppTypes($app) {
246
-		//load the cache
247
-		if (count(self::$appTypes) == 0) {
248
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
249
-		}
250
-
251
-		if (isset(self::$appTypes[$app])) {
252
-			return explode(',', self::$appTypes[$app]);
253
-		} else {
254
-			return array();
255
-		}
256
-	}
257
-
258
-	/**
259
-	 * read app types from info.xml and cache them in the database
260
-	 */
261
-	public static function setAppTypes($app) {
262
-		$appData = self::getAppInfo($app);
263
-		if(!is_array($appData)) {
264
-			return;
265
-		}
266
-
267
-		if (isset($appData['types'])) {
268
-			$appTypes = implode(',', $appData['types']);
269
-		} else {
270
-			$appTypes = '';
271
-			$appData['types'] = [];
272
-		}
273
-
274
-		\OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
275
-
276
-		if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
277
-			$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'yes');
278
-			if ($enabled !== 'yes' && $enabled !== 'no') {
279
-				\OC::$server->getAppConfig()->setValue($app, 'enabled', 'yes');
280
-			}
281
-		}
282
-	}
283
-
284
-	/**
285
-	 * check if app is shipped
286
-	 *
287
-	 * @param string $appId the id of the app to check
288
-	 * @return bool
289
-	 *
290
-	 * Check if an app that is installed is a shipped app or installed from the appstore.
291
-	 */
292
-	public static function isShipped($appId) {
293
-		return \OC::$server->getAppManager()->isShipped($appId);
294
-	}
295
-
296
-	/**
297
-	 * get all enabled apps
298
-	 */
299
-	protected static $enabledAppsCache = array();
300
-
301
-	/**
302
-	 * Returns apps enabled for the current user.
303
-	 *
304
-	 * @param bool $forceRefresh whether to refresh the cache
305
-	 * @param bool $all whether to return apps for all users, not only the
306
-	 * currently logged in one
307
-	 * @return string[]
308
-	 */
309
-	public static function getEnabledApps($forceRefresh = false, $all = false) {
310
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
311
-			return array();
312
-		}
313
-		// in incognito mode or when logged out, $user will be false,
314
-		// which is also the case during an upgrade
315
-		$appManager = \OC::$server->getAppManager();
316
-		if ($all) {
317
-			$user = null;
318
-		} else {
319
-			$user = \OC::$server->getUserSession()->getUser();
320
-		}
321
-
322
-		if (is_null($user)) {
323
-			$apps = $appManager->getInstalledApps();
324
-		} else {
325
-			$apps = $appManager->getEnabledAppsForUser($user);
326
-		}
327
-		$apps = array_filter($apps, function ($app) {
328
-			return $app !== 'files';//we add this manually
329
-		});
330
-		sort($apps);
331
-		array_unshift($apps, 'files');
332
-		return $apps;
333
-	}
334
-
335
-	/**
336
-	 * checks whether or not an app is enabled
337
-	 *
338
-	 * @param string $app app
339
-	 * @return bool
340
-	 *
341
-	 * This function checks whether or not an app is enabled.
342
-	 */
343
-	public static function isEnabled($app) {
344
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
345
-	}
346
-
347
-	/**
348
-	 * enables an app
349
-	 *
350
-	 * @param string $appId
351
-	 * @param array $groups (optional) when set, only these groups will have access to the app
352
-	 * @throws \Exception
353
-	 * @return void
354
-	 *
355
-	 * This function set an app as enabled in appconfig.
356
-	 */
357
-	public function enable($appId,
358
-						   $groups = null) {
359
-		self::$enabledAppsCache = []; // flush
360
-		$l = \OC::$server->getL10N('core');
361
-		$config = \OC::$server->getConfig();
362
-
363
-		// Check if app is already downloaded
364
-		$installer = new Installer(
365
-			\OC::$server->getAppFetcher(),
366
-			\OC::$server->getHTTPClientService(),
367
-			\OC::$server->getTempManager(),
368
-			\OC::$server->getLogger()
369
-		);
370
-		$isDownloaded = $installer->isDownloaded($appId);
371
-
372
-		if(!$isDownloaded) {
373
-			$installer->downloadApp($appId);
374
-		}
375
-
376
-		if (!Installer::isInstalled($appId)) {
377
-			$appId = self::installApp(
378
-				$appId,
379
-				$config,
380
-				$l
381
-			);
382
-			$appPath = self::getAppPath($appId);
383
-			self::registerAutoloading($appId, $appPath);
384
-			$installer->installApp($appId);
385
-		} else {
386
-			// check for required dependencies
387
-			$info = self::getAppInfo($appId);
388
-			self::checkAppDependencies($config, $l, $info);
389
-			$appPath = self::getAppPath($appId);
390
-			self::registerAutoloading($appId, $appPath);
391
-			$installer->installApp($appId);
392
-		}
393
-
394
-		$appManager = \OC::$server->getAppManager();
395
-		if (!is_null($groups)) {
396
-			$groupManager = \OC::$server->getGroupManager();
397
-			$groupsList = [];
398
-			foreach ($groups as $group) {
399
-				$groupItem = $groupManager->get($group);
400
-				if ($groupItem instanceof \OCP\IGroup) {
401
-					$groupsList[] = $groupManager->get($group);
402
-				}
403
-			}
404
-			$appManager->enableAppForGroups($appId, $groupsList);
405
-		} else {
406
-			$appManager->enableApp($appId);
407
-		}
408
-
409
-		$info = self::getAppInfo($appId);
410
-		if(isset($info['settings']) && is_array($info['settings'])) {
411
-			$appPath = self::getAppPath($appId);
412
-			self::registerAutoloading($appId, $appPath);
413
-			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
414
-		}
415
-	}
416
-
417
-	/**
418
-	 * @param string $app
419
-	 * @return bool
420
-	 */
421
-	public static function removeApp($app) {
422
-		if (self::isShipped($app)) {
423
-			return false;
424
-		}
425
-
426
-		$installer = new Installer(
427
-			\OC::$server->getAppFetcher(),
428
-			\OC::$server->getHTTPClientService(),
429
-			\OC::$server->getTempManager(),
430
-			\OC::$server->getLogger()
431
-		);
432
-		return $installer->removeApp($app);
433
-	}
434
-
435
-	/**
436
-	 * This function set an app as disabled in appconfig.
437
-	 *
438
-	 * @param string $app app
439
-	 * @throws Exception
440
-	 */
441
-	public static function disable($app) {
442
-		// flush
443
-		self::$enabledAppsCache = array();
444
-
445
-		// run uninstall steps
446
-		$appData = OC_App::getAppInfo($app);
447
-		if (!is_null($appData)) {
448
-			OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
449
-		}
450
-
451
-		// emit disable hook - needed anymore ?
452
-		\OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
453
-
454
-		// finally disable it
455
-		$appManager = \OC::$server->getAppManager();
456
-		$appManager->disableApp($app);
457
-	}
458
-
459
-	/**
460
-	 * Returns the Settings Navigation
461
-	 *
462
-	 * @return string[]
463
-	 *
464
-	 * This function returns an array containing all settings pages added. The
465
-	 * entries are sorted by the key 'order' ascending.
466
-	 */
467
-	public static function getSettingsNavigation() {
468
-		$l = \OC::$server->getL10N('lib');
469
-		$urlGenerator = \OC::$server->getURLGenerator();
470
-
471
-		$settings = array();
472
-		// by default, settings only contain the help menu
473
-		if (\OC::$server->getSystemConfig()->getValue('knowledgebaseenabled', true)) {
474
-			$settings = array(
475
-				array(
476
-					"id" => "help",
477
-					"order" => 4,
478
-					"href" => $urlGenerator->linkToRoute('settings_help'),
479
-					"name" => $l->t("Help"),
480
-					"icon" => $urlGenerator->imagePath("settings", "help.svg")
481
-				)
482
-			);
483
-		}
484
-
485
-		// if the user is logged-in
486
-		if (\OC::$server->getUserSession()->isLoggedIn()) {
487
-			// personal menu
488
-			$settings[] = array(
489
-				"id" => "personal",
490
-				"order" => 1,
491
-				"href" => $urlGenerator->linkToRoute('settings_personal'),
492
-				"name" => $l->t("Personal"),
493
-				"icon" => $urlGenerator->imagePath("settings", "personal.svg")
494
-			);
495
-
496
-			//SubAdmins are also allowed to access user management
497
-			$userObject = \OC::$server->getUserSession()->getUser();
498
-			$isSubAdmin = false;
499
-			if($userObject !== null) {
500
-				$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
501
-			}
502
-			if ($isSubAdmin) {
503
-				// admin users menu
504
-				$settings[] = array(
505
-					"id" => "core_users",
506
-					"order" => 3,
507
-					"href" => $urlGenerator->linkToRoute('settings_users'),
508
-					"name" => $l->t("Users"),
509
-					"icon" => $urlGenerator->imagePath("settings", "users.svg")
510
-				);
511
-			}
512
-
513
-			// if the user is an admin
514
-			if (OC_User::isAdminUser(OC_User::getUser())) {
515
-				// admin settings
516
-				$settings[] = array(
517
-					"id" => "admin",
518
-					"order" => 2,
519
-					"href" => $urlGenerator->linkToRoute('settings.AdminSettings.index'),
520
-					"name" => $l->t("Admin"),
521
-					"icon" => $urlGenerator->imagePath("settings", "admin.svg")
522
-				);
523
-			}
524
-		}
525
-
526
-		$navigation = self::proceedNavigation($settings);
527
-		return $navigation;
528
-	}
529
-
530
-	// This is private as well. It simply works, so don't ask for more details
531
-	private static function proceedNavigation($list) {
532
-		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
533
-		foreach ($list as &$navEntry) {
534
-			if ($navEntry['id'] == $activeApp) {
535
-				$navEntry['active'] = true;
536
-			} else {
537
-				$navEntry['active'] = false;
538
-			}
539
-		}
540
-		unset($navEntry);
541
-
542
-		usort($list, function($a, $b) {
543
-			if (isset($a['order']) && isset($b['order'])) {
544
-				return ($a['order'] < $b['order']) ? -1 : 1;
545
-			} else if (isset($a['order']) || isset($b['order'])) {
546
-				return isset($a['order']) ? -1 : 1;
547
-			} else {
548
-				return ($a['name'] < $b['name']) ? -1 : 1;
549
-			}
550
-		});
551
-
552
-		return $list;
553
-	}
554
-
555
-	/**
556
-	 * Get the path where to install apps
557
-	 *
558
-	 * @return string|false
559
-	 */
560
-	public static function getInstallPath() {
561
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
562
-			return false;
563
-		}
564
-
565
-		foreach (OC::$APPSROOTS as $dir) {
566
-			if (isset($dir['writable']) && $dir['writable'] === true) {
567
-				return $dir['path'];
568
-			}
569
-		}
570
-
571
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
572
-		return null;
573
-	}
574
-
575
-
576
-	/**
577
-	 * search for an app in all app-directories
578
-	 *
579
-	 * @param string $appId
580
-	 * @return false|string
581
-	 */
582
-	public static function findAppInDirectories($appId) {
583
-		$sanitizedAppId = self::cleanAppId($appId);
584
-		if($sanitizedAppId !== $appId) {
585
-			return false;
586
-		}
587
-		static $app_dir = array();
588
-
589
-		if (isset($app_dir[$appId])) {
590
-			return $app_dir[$appId];
591
-		}
592
-
593
-		$possibleApps = array();
594
-		foreach (OC::$APPSROOTS as $dir) {
595
-			if (file_exists($dir['path'] . '/' . $appId)) {
596
-				$possibleApps[] = $dir;
597
-			}
598
-		}
599
-
600
-		if (empty($possibleApps)) {
601
-			return false;
602
-		} elseif (count($possibleApps) === 1) {
603
-			$dir = array_shift($possibleApps);
604
-			$app_dir[$appId] = $dir;
605
-			return $dir;
606
-		} else {
607
-			$versionToLoad = array();
608
-			foreach ($possibleApps as $possibleApp) {
609
-				$version = self::getAppVersionByPath($possibleApp['path']);
610
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
611
-					$versionToLoad = array(
612
-						'dir' => $possibleApp,
613
-						'version' => $version,
614
-					);
615
-				}
616
-			}
617
-			$app_dir[$appId] = $versionToLoad['dir'];
618
-			return $versionToLoad['dir'];
619
-			//TODO - write test
620
-		}
621
-	}
622
-
623
-	/**
624
-	 * Get the directory for the given app.
625
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
626
-	 *
627
-	 * @param string $appId
628
-	 * @return string|false
629
-	 */
630
-	public static function getAppPath($appId) {
631
-		if ($appId === null || trim($appId) === '') {
632
-			return false;
633
-		}
634
-
635
-		if (($dir = self::findAppInDirectories($appId)) != false) {
636
-			return $dir['path'] . '/' . $appId;
637
-		}
638
-		return false;
639
-	}
640
-
641
-	/**
642
-	 * Get the path for the given app on the access
643
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
644
-	 *
645
-	 * @param string $appId
646
-	 * @return string|false
647
-	 */
648
-	public static function getAppWebPath($appId) {
649
-		if (($dir = self::findAppInDirectories($appId)) != false) {
650
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
651
-		}
652
-		return false;
653
-	}
654
-
655
-	/**
656
-	 * get the last version of the app from appinfo/info.xml
657
-	 *
658
-	 * @param string $appId
659
-	 * @param bool $useCache
660
-	 * @return string
661
-	 */
662
-	public static function getAppVersion($appId, $useCache = true) {
663
-		if($useCache && isset(self::$appVersion[$appId])) {
664
-			return self::$appVersion[$appId];
665
-		}
666
-
667
-		$file = self::getAppPath($appId);
668
-		self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
669
-		return self::$appVersion[$appId];
670
-	}
671
-
672
-	/**
673
-	 * get app's version based on it's path
674
-	 *
675
-	 * @param string $path
676
-	 * @return string
677
-	 */
678
-	public static function getAppVersionByPath($path) {
679
-		$infoFile = $path . '/appinfo/info.xml';
680
-		$appData = self::getAppInfo($infoFile, true);
681
-		return isset($appData['version']) ? $appData['version'] : '';
682
-	}
683
-
684
-
685
-	/**
686
-	 * Read all app metadata from the info.xml file
687
-	 *
688
-	 * @param string $appId id of the app or the path of the info.xml file
689
-	 * @param bool $path
690
-	 * @param string $lang
691
-	 * @return array|null
692
-	 * @note all data is read from info.xml, not just pre-defined fields
693
-	 */
694
-	public static function getAppInfo($appId, $path = false, $lang = null) {
695
-		if ($path) {
696
-			$file = $appId;
697
-		} else {
698
-			if ($lang === null && isset(self::$appInfo[$appId])) {
699
-				return self::$appInfo[$appId];
700
-			}
701
-			$appPath = self::getAppPath($appId);
702
-			if($appPath === false) {
703
-				return null;
704
-			}
705
-			$file = $appPath . '/appinfo/info.xml';
706
-		}
707
-
708
-		$parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
709
-		$data = $parser->parse($file);
710
-
711
-		if (is_array($data)) {
712
-			$data = OC_App::parseAppInfo($data, $lang);
713
-		}
714
-		if(isset($data['ocsid'])) {
715
-			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
716
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
717
-				$data['ocsid'] = $storedId;
718
-			}
719
-		}
720
-
721
-		if ($lang === null) {
722
-			self::$appInfo[$appId] = $data;
723
-		}
724
-
725
-		return $data;
726
-	}
727
-
728
-	/**
729
-	 * Returns the navigation
730
-	 *
731
-	 * @return array
732
-	 *
733
-	 * This function returns an array containing all entries added. The
734
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
735
-	 * given for each app the following keys exist:
736
-	 *   - active: boolean, signals if the user is on this navigation entry
737
-	 */
738
-	public static function getNavigation() {
739
-		$entries = OC::$server->getNavigationManager()->getAll();
740
-		$navigation = self::proceedNavigation($entries);
741
-		return $navigation;
742
-	}
743
-
744
-	/**
745
-	 * get the id of loaded app
746
-	 *
747
-	 * @return string
748
-	 */
749
-	public static function getCurrentApp() {
750
-		$request = \OC::$server->getRequest();
751
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
752
-		$topFolder = substr($script, 0, strpos($script, '/'));
753
-		if (empty($topFolder)) {
754
-			$path_info = $request->getPathInfo();
755
-			if ($path_info) {
756
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
757
-			}
758
-		}
759
-		if ($topFolder == 'apps') {
760
-			$length = strlen($topFolder);
761
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
762
-		} else {
763
-			return $topFolder;
764
-		}
765
-	}
766
-
767
-	/**
768
-	 * @param string $type
769
-	 * @return array
770
-	 */
771
-	public static function getForms($type) {
772
-		$forms = array();
773
-		switch ($type) {
774
-			case 'admin':
775
-				$source = self::$adminForms;
776
-				break;
777
-			case 'personal':
778
-				$source = self::$personalForms;
779
-				break;
780
-			default:
781
-				return array();
782
-		}
783
-		foreach ($source as $form) {
784
-			$forms[] = include $form;
785
-		}
786
-		return $forms;
787
-	}
788
-
789
-	/**
790
-	 * register an admin form to be shown
791
-	 *
792
-	 * @param string $app
793
-	 * @param string $page
794
-	 */
795
-	public static function registerAdmin($app, $page) {
796
-		self::$adminForms[] = $app . '/' . $page . '.php';
797
-	}
798
-
799
-	/**
800
-	 * register a personal form to be shown
801
-	 * @param string $app
802
-	 * @param string $page
803
-	 */
804
-	public static function registerPersonal($app, $page) {
805
-		self::$personalForms[] = $app . '/' . $page . '.php';
806
-	}
807
-
808
-	/**
809
-	 * @param array $entry
810
-	 */
811
-	public static function registerLogIn(array $entry) {
812
-		self::$altLogin[] = $entry;
813
-	}
814
-
815
-	/**
816
-	 * @return array
817
-	 */
818
-	public static function getAlternativeLogIns() {
819
-		return self::$altLogin;
820
-	}
821
-
822
-	/**
823
-	 * get a list of all apps in the apps folder
824
-	 *
825
-	 * @return array an array of app names (string IDs)
826
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
827
-	 */
828
-	public static function getAllApps() {
829
-
830
-		$apps = array();
831
-
832
-		foreach (OC::$APPSROOTS as $apps_dir) {
833
-			if (!is_readable($apps_dir['path'])) {
834
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
835
-				continue;
836
-			}
837
-			$dh = opendir($apps_dir['path']);
838
-
839
-			if (is_resource($dh)) {
840
-				while (($file = readdir($dh)) !== false) {
841
-
842
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
843
-
844
-						$apps[] = $file;
845
-					}
846
-				}
847
-			}
848
-		}
849
-
850
-		return $apps;
851
-	}
852
-
853
-	/**
854
-	 * List all apps, this is used in apps.php
855
-	 *
856
-	 * @return array
857
-	 */
858
-	public function listAllApps() {
859
-		$installedApps = OC_App::getAllApps();
860
-
861
-		//we don't want to show configuration for these
862
-		$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
863
-		$appList = array();
864
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
865
-		$urlGenerator = \OC::$server->getURLGenerator();
866
-
867
-		foreach ($installedApps as $app) {
868
-			if (array_search($app, $blacklist) === false) {
869
-
870
-				$info = OC_App::getAppInfo($app, false, $langCode);
871
-				if (!is_array($info)) {
872
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
873
-					continue;
874
-				}
875
-
876
-				if (!isset($info['name'])) {
877
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
878
-					continue;
879
-				}
880
-
881
-				$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
882
-				$info['groups'] = null;
883
-				if ($enabled === 'yes') {
884
-					$active = true;
885
-				} else if ($enabled === 'no') {
886
-					$active = false;
887
-				} else {
888
-					$active = true;
889
-					$info['groups'] = $enabled;
890
-				}
891
-
892
-				$info['active'] = $active;
893
-
894
-				if (self::isShipped($app)) {
895
-					$info['internal'] = true;
896
-					$info['level'] = self::officialApp;
897
-					$info['removable'] = false;
898
-				} else {
899
-					$info['internal'] = false;
900
-					$info['removable'] = true;
901
-				}
902
-
903
-				$appPath = self::getAppPath($app);
904
-				if($appPath !== false) {
905
-					$appIcon = $appPath . '/img/' . $app . '.svg';
906
-					if (file_exists($appIcon)) {
907
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
908
-						$info['previewAsIcon'] = true;
909
-					} else {
910
-						$appIcon = $appPath . '/img/app.svg';
911
-						if (file_exists($appIcon)) {
912
-							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
913
-							$info['previewAsIcon'] = true;
914
-						}
915
-					}
916
-				}
917
-				// fix documentation
918
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
919
-					foreach ($info['documentation'] as $key => $url) {
920
-						// If it is not an absolute URL we assume it is a key
921
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
922
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
923
-							$url = $urlGenerator->linkToDocs($url);
924
-						}
925
-
926
-						$info['documentation'][$key] = $url;
927
-					}
928
-				}
929
-
930
-				$info['version'] = OC_App::getAppVersion($app);
931
-				$appList[] = $info;
932
-			}
933
-		}
934
-
935
-		return $appList;
936
-	}
937
-
938
-	/**
939
-	 * Returns the internal app ID or false
940
-	 * @param string $ocsID
941
-	 * @return string|false
942
-	 */
943
-	public static function getInternalAppIdByOcs($ocsID) {
944
-		if(is_numeric($ocsID)) {
945
-			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
946
-			if(array_search($ocsID, $idArray)) {
947
-				return array_search($ocsID, $idArray);
948
-			}
949
-		}
950
-		return false;
951
-	}
952
-
953
-	public static function shouldUpgrade($app) {
954
-		$versions = self::getAppVersions();
955
-		$currentVersion = OC_App::getAppVersion($app);
956
-		if ($currentVersion && isset($versions[$app])) {
957
-			$installedVersion = $versions[$app];
958
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
959
-				return true;
960
-			}
961
-		}
962
-		return false;
963
-	}
964
-
965
-	/**
966
-	 * Adjust the number of version parts of $version1 to match
967
-	 * the number of version parts of $version2.
968
-	 *
969
-	 * @param string $version1 version to adjust
970
-	 * @param string $version2 version to take the number of parts from
971
-	 * @return string shortened $version1
972
-	 */
973
-	private static function adjustVersionParts($version1, $version2) {
974
-		$version1 = explode('.', $version1);
975
-		$version2 = explode('.', $version2);
976
-		// reduce $version1 to match the number of parts in $version2
977
-		while (count($version1) > count($version2)) {
978
-			array_pop($version1);
979
-		}
980
-		// if $version1 does not have enough parts, add some
981
-		while (count($version1) < count($version2)) {
982
-			$version1[] = '0';
983
-		}
984
-		return implode('.', $version1);
985
-	}
986
-
987
-	/**
988
-	 * Check whether the current ownCloud version matches the given
989
-	 * application's version requirements.
990
-	 *
991
-	 * The comparison is made based on the number of parts that the
992
-	 * app info version has. For example for ownCloud 6.0.3 if the
993
-	 * app info version is expecting version 6.0, the comparison is
994
-	 * made on the first two parts of the ownCloud version.
995
-	 * This means that it's possible to specify "requiremin" => 6
996
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
997
-	 *
998
-	 * @param string $ocVersion ownCloud version to check against
999
-	 * @param array $appInfo app info (from xml)
1000
-	 *
1001
-	 * @return boolean true if compatible, otherwise false
1002
-	 */
1003
-	public static function isAppCompatible($ocVersion, $appInfo) {
1004
-		$requireMin = '';
1005
-		$requireMax = '';
1006
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
1007
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
1008
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
1009
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
1010
-		} else if (isset($appInfo['requiremin'])) {
1011
-			$requireMin = $appInfo['requiremin'];
1012
-		} else if (isset($appInfo['require'])) {
1013
-			$requireMin = $appInfo['require'];
1014
-		}
1015
-
1016
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
1017
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
1018
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
1019
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
1020
-		} else if (isset($appInfo['requiremax'])) {
1021
-			$requireMax = $appInfo['requiremax'];
1022
-		}
1023
-
1024
-		if (is_array($ocVersion)) {
1025
-			$ocVersion = implode('.', $ocVersion);
1026
-		}
1027
-
1028
-		if (!empty($requireMin)
1029
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
1030
-		) {
1031
-
1032
-			return false;
1033
-		}
1034
-
1035
-		if (!empty($requireMax)
1036
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
1037
-		) {
1038
-			return false;
1039
-		}
1040
-
1041
-		return true;
1042
-	}
1043
-
1044
-	/**
1045
-	 * get the installed version of all apps
1046
-	 */
1047
-	public static function getAppVersions() {
1048
-		static $versions;
1049
-
1050
-		if(!$versions) {
1051
-			$appConfig = \OC::$server->getAppConfig();
1052
-			$versions = $appConfig->getValues(false, 'installed_version');
1053
-		}
1054
-		return $versions;
1055
-	}
1056
-
1057
-	/**
1058
-	 * @param string $app
1059
-	 * @param \OCP\IConfig $config
1060
-	 * @param \OCP\IL10N $l
1061
-	 * @return bool
1062
-	 *
1063
-	 * @throws Exception if app is not compatible with this version of ownCloud
1064
-	 * @throws Exception if no app-name was specified
1065
-	 */
1066
-	public function installApp($app,
1067
-							   \OCP\IConfig $config,
1068
-							   \OCP\IL10N $l) {
1069
-		if ($app !== false) {
1070
-			// check if the app is compatible with this version of ownCloud
1071
-			$info = self::getAppInfo($app);
1072
-			if(!is_array($info)) {
1073
-				throw new \Exception(
1074
-					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1075
-						[$info['name']]
1076
-					)
1077
-				);
1078
-			}
1079
-
1080
-			$version = \OCP\Util::getVersion();
1081
-			if (!self::isAppCompatible($version, $info)) {
1082
-				throw new \Exception(
1083
-					$l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
1084
-						array($info['name'])
1085
-					)
1086
-				);
1087
-			}
1088
-
1089
-			// check for required dependencies
1090
-			self::checkAppDependencies($config, $l, $info);
1091
-
1092
-			$config->setAppValue($app, 'enabled', 'yes');
1093
-			if (isset($appData['id'])) {
1094
-				$config->setAppValue($app, 'ocsid', $appData['id']);
1095
-			}
1096
-
1097
-			if(isset($info['settings']) && is_array($info['settings'])) {
1098
-				$appPath = self::getAppPath($app);
1099
-				self::registerAutoloading($app, $appPath);
1100
-				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
1101
-			}
1102
-
1103
-			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1104
-		} else {
1105
-			if(empty($appName) ) {
1106
-				throw new \Exception($l->t("No app name specified"));
1107
-			} else {
1108
-				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1109
-			}
1110
-		}
1111
-
1112
-		return $app;
1113
-	}
1114
-
1115
-	/**
1116
-	 * update the database for the app and call the update script
1117
-	 *
1118
-	 * @param string $appId
1119
-	 * @return bool
1120
-	 */
1121
-	public static function updateApp($appId) {
1122
-		$appPath = self::getAppPath($appId);
1123
-		if($appPath === false) {
1124
-			return false;
1125
-		}
1126
-		$appData = self::getAppInfo($appId);
1127
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1128
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1129
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1130
-		}
1131
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1132
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1133
-		unset(self::$appVersion[$appId]);
1134
-		// run upgrade code
1135
-		if (file_exists($appPath . '/appinfo/update.php')) {
1136
-			self::loadApp($appId);
1137
-			include $appPath . '/appinfo/update.php';
1138
-		}
1139
-		self::setupBackgroundJobs($appData['background-jobs']);
1140
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1141
-			$appPath = self::getAppPath($appId);
1142
-			self::registerAutoloading($appId, $appPath);
1143
-			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1144
-		}
1145
-
1146
-		//set remote/public handlers
1147
-		if (array_key_exists('ocsid', $appData)) {
1148
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1149
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1150
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1151
-		}
1152
-		foreach ($appData['remote'] as $name => $path) {
1153
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1154
-		}
1155
-		foreach ($appData['public'] as $name => $path) {
1156
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1157
-		}
1158
-
1159
-		self::setAppTypes($appId);
1160
-
1161
-		$version = \OC_App::getAppVersion($appId);
1162
-		\OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1163
-
1164
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1165
-			ManagerEvent::EVENT_APP_UPDATE, $appId
1166
-		));
1167
-
1168
-		return true;
1169
-	}
1170
-
1171
-	/**
1172
-	 * @param string $appId
1173
-	 * @param string[] $steps
1174
-	 * @throws \OC\NeedsUpdateException
1175
-	 */
1176
-	public static function executeRepairSteps($appId, array $steps) {
1177
-		if (empty($steps)) {
1178
-			return;
1179
-		}
1180
-		// load the app
1181
-		self::loadApp($appId);
1182
-
1183
-		$dispatcher = OC::$server->getEventDispatcher();
1184
-
1185
-		// load the steps
1186
-		$r = new Repair([], $dispatcher);
1187
-		foreach ($steps as $step) {
1188
-			try {
1189
-				$r->addStep($step);
1190
-			} catch (Exception $ex) {
1191
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1192
-				\OC::$server->getLogger()->logException($ex);
1193
-			}
1194
-		}
1195
-		// run the steps
1196
-		$r->run();
1197
-	}
1198
-
1199
-	public static function setupBackgroundJobs(array $jobs) {
1200
-		$queue = \OC::$server->getJobList();
1201
-		foreach ($jobs as $job) {
1202
-			$queue->add($job);
1203
-		}
1204
-	}
1205
-
1206
-	/**
1207
-	 * @param string $appId
1208
-	 * @param string[] $steps
1209
-	 */
1210
-	private static function setupLiveMigrations($appId, array $steps) {
1211
-		$queue = \OC::$server->getJobList();
1212
-		foreach ($steps as $step) {
1213
-			$queue->add('OC\Migration\BackgroundRepair', [
1214
-				'app' => $appId,
1215
-				'step' => $step]);
1216
-		}
1217
-	}
1218
-
1219
-	/**
1220
-	 * @param string $appId
1221
-	 * @return \OC\Files\View|false
1222
-	 */
1223
-	public static function getStorage($appId) {
1224
-		if (OC_App::isEnabled($appId)) { //sanity check
1225
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
1226
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1227
-				if (!$view->file_exists($appId)) {
1228
-					$view->mkdir($appId);
1229
-				}
1230
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1231
-			} else {
1232
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1233
-				return false;
1234
-			}
1235
-		} else {
1236
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1237
-			return false;
1238
-		}
1239
-	}
1240
-
1241
-	protected static function findBestL10NOption($options, $lang) {
1242
-		$fallback = $similarLangFallback = $englishFallback = false;
1243
-
1244
-		$lang = strtolower($lang);
1245
-		$similarLang = $lang;
1246
-		if (strpos($similarLang, '_')) {
1247
-			// For "de_DE" we want to find "de" and the other way around
1248
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1249
-		}
1250
-
1251
-		foreach ($options as $option) {
1252
-			if (is_array($option)) {
1253
-				if ($fallback === false) {
1254
-					$fallback = $option['@value'];
1255
-				}
1256
-
1257
-				if (!isset($option['@attributes']['lang'])) {
1258
-					continue;
1259
-				}
1260
-
1261
-				$attributeLang = strtolower($option['@attributes']['lang']);
1262
-				if ($attributeLang === $lang) {
1263
-					return $option['@value'];
1264
-				}
1265
-
1266
-				if ($attributeLang === $similarLang) {
1267
-					$similarLangFallback = $option['@value'];
1268
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1269
-					if ($similarLangFallback === false) {
1270
-						$similarLangFallback =  $option['@value'];
1271
-					}
1272
-				}
1273
-			} else {
1274
-				$englishFallback = $option;
1275
-			}
1276
-		}
1277
-
1278
-		if ($similarLangFallback !== false) {
1279
-			return $similarLangFallback;
1280
-		} else if ($englishFallback !== false) {
1281
-			return $englishFallback;
1282
-		}
1283
-		return (string) $fallback;
1284
-	}
1285
-
1286
-	/**
1287
-	 * parses the app data array and enhanced the 'description' value
1288
-	 *
1289
-	 * @param array $data the app data
1290
-	 * @param string $lang
1291
-	 * @return array improved app data
1292
-	 */
1293
-	public static function parseAppInfo(array $data, $lang = null) {
1294
-
1295
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1296
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1297
-		}
1298
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1299
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1300
-		}
1301
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1302
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1303
-		} else if (isset($data['description']) && is_string($data['description'])) {
1304
-			$data['description'] = trim($data['description']);
1305
-		} else  {
1306
-			$data['description'] = '';
1307
-		}
1308
-
1309
-		return $data;
1310
-	}
1311
-
1312
-	/**
1313
-	 * @param \OCP\IConfig $config
1314
-	 * @param \OCP\IL10N $l
1315
-	 * @param array $info
1316
-	 * @throws \Exception
1317
-	 */
1318
-	protected static function checkAppDependencies($config, $l, $info) {
1319
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1320
-		$missing = $dependencyAnalyzer->analyze($info);
1321
-		if (!empty($missing)) {
1322
-			$missingMsg = join(PHP_EOL, $missing);
1323
-			throw new \Exception(
1324
-				$l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1325
-					[$info['name'], $missingMsg]
1326
-				)
1327
-			);
1328
-		}
1329
-	}
64
+    static private $appVersion = [];
65
+    static private $adminForms = array();
66
+    static private $personalForms = array();
67
+    static private $appInfo = array();
68
+    static private $appTypes = array();
69
+    static private $loadedApps = array();
70
+    static private $altLogin = array();
71
+    static private $alreadyRegistered = [];
72
+    const officialApp = 200;
73
+
74
+    /**
75
+     * clean the appId
76
+     *
77
+     * @param string|boolean $app AppId that needs to be cleaned
78
+     * @return string
79
+     */
80
+    public static function cleanAppId($app) {
81
+        return str_replace(array('\0', '/', '\\', '..'), '', $app);
82
+    }
83
+
84
+    /**
85
+     * Check if an app is loaded
86
+     *
87
+     * @param string $app
88
+     * @return bool
89
+     */
90
+    public static function isAppLoaded($app) {
91
+        return in_array($app, self::$loadedApps, true);
92
+    }
93
+
94
+    /**
95
+     * loads all apps
96
+     *
97
+     * @param string[] | string | null $types
98
+     * @return bool
99
+     *
100
+     * This function walks through the ownCloud directory and loads all apps
101
+     * it can find. A directory contains an app if the file /appinfo/info.xml
102
+     * exists.
103
+     *
104
+     * if $types is set, only apps of those types will be loaded
105
+     */
106
+    public static function loadApps($types = null) {
107
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
108
+            return false;
109
+        }
110
+        // Load the enabled apps here
111
+        $apps = self::getEnabledApps();
112
+
113
+        // Add each apps' folder as allowed class path
114
+        foreach($apps as $app) {
115
+            $path = self::getAppPath($app);
116
+            if($path !== false) {
117
+                self::registerAutoloading($app, $path);
118
+            }
119
+        }
120
+
121
+        // prevent app.php from printing output
122
+        ob_start();
123
+        foreach ($apps as $app) {
124
+            if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
125
+                self::loadApp($app);
126
+            }
127
+        }
128
+        ob_end_clean();
129
+
130
+        return true;
131
+    }
132
+
133
+    /**
134
+     * load a single app
135
+     *
136
+     * @param string $app
137
+     */
138
+    public static function loadApp($app) {
139
+        self::$loadedApps[] = $app;
140
+        $appPath = self::getAppPath($app);
141
+        if($appPath === false) {
142
+            return;
143
+        }
144
+
145
+        // in case someone calls loadApp() directly
146
+        self::registerAutoloading($app, $appPath);
147
+
148
+        if (is_file($appPath . '/appinfo/app.php')) {
149
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
150
+            self::requireAppFile($app);
151
+            if (self::isType($app, array('authentication'))) {
152
+                // since authentication apps affect the "is app enabled for group" check,
153
+                // the enabled apps cache needs to be cleared to make sure that the
154
+                // next time getEnableApps() is called it will also include apps that were
155
+                // enabled for groups
156
+                self::$enabledAppsCache = array();
157
+            }
158
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
159
+        }
160
+
161
+        $info = self::getAppInfo($app);
162
+        if (!empty($info['activity']['filters'])) {
163
+            foreach ($info['activity']['filters'] as $filter) {
164
+                \OC::$server->getActivityManager()->registerFilter($filter);
165
+            }
166
+        }
167
+        if (!empty($info['activity']['settings'])) {
168
+            foreach ($info['activity']['settings'] as $setting) {
169
+                \OC::$server->getActivityManager()->registerSetting($setting);
170
+            }
171
+        }
172
+        if (!empty($info['activity']['providers'])) {
173
+            foreach ($info['activity']['providers'] as $provider) {
174
+                \OC::$server->getActivityManager()->registerProvider($provider);
175
+            }
176
+        }
177
+    }
178
+
179
+    /**
180
+     * @internal
181
+     * @param string $app
182
+     * @param string $path
183
+     */
184
+    public static function registerAutoloading($app, $path) {
185
+        $key = $app . '-' . $path;
186
+        if(isset(self::$alreadyRegistered[$key])) {
187
+            return;
188
+        }
189
+        self::$alreadyRegistered[$key] = true;
190
+        // Register on PSR-4 composer autoloader
191
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
192
+        \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
193
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
194
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
195
+        }
196
+
197
+        // Register on legacy autoloader
198
+        \OC::$loader->addValidRoot($path);
199
+    }
200
+
201
+    /**
202
+     * Load app.php from the given app
203
+     *
204
+     * @param string $app app name
205
+     */
206
+    private static function requireAppFile($app) {
207
+        try {
208
+            // encapsulated here to avoid variable scope conflicts
209
+            require_once $app . '/appinfo/app.php';
210
+        } catch (Error $ex) {
211
+            \OC::$server->getLogger()->logException($ex);
212
+            $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
213
+            if (!in_array($app, $blacklist)) {
214
+                self::disable($app);
215
+            }
216
+        }
217
+    }
218
+
219
+    /**
220
+     * check if an app is of a specific type
221
+     *
222
+     * @param string $app
223
+     * @param string|array $types
224
+     * @return bool
225
+     */
226
+    public static function isType($app, $types) {
227
+        if (is_string($types)) {
228
+            $types = array($types);
229
+        }
230
+        $appTypes = self::getAppTypes($app);
231
+        foreach ($types as $type) {
232
+            if (array_search($type, $appTypes) !== false) {
233
+                return true;
234
+            }
235
+        }
236
+        return false;
237
+    }
238
+
239
+    /**
240
+     * get the types of an app
241
+     *
242
+     * @param string $app
243
+     * @return array
244
+     */
245
+    private static function getAppTypes($app) {
246
+        //load the cache
247
+        if (count(self::$appTypes) == 0) {
248
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
249
+        }
250
+
251
+        if (isset(self::$appTypes[$app])) {
252
+            return explode(',', self::$appTypes[$app]);
253
+        } else {
254
+            return array();
255
+        }
256
+    }
257
+
258
+    /**
259
+     * read app types from info.xml and cache them in the database
260
+     */
261
+    public static function setAppTypes($app) {
262
+        $appData = self::getAppInfo($app);
263
+        if(!is_array($appData)) {
264
+            return;
265
+        }
266
+
267
+        if (isset($appData['types'])) {
268
+            $appTypes = implode(',', $appData['types']);
269
+        } else {
270
+            $appTypes = '';
271
+            $appData['types'] = [];
272
+        }
273
+
274
+        \OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
275
+
276
+        if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
277
+            $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'yes');
278
+            if ($enabled !== 'yes' && $enabled !== 'no') {
279
+                \OC::$server->getAppConfig()->setValue($app, 'enabled', 'yes');
280
+            }
281
+        }
282
+    }
283
+
284
+    /**
285
+     * check if app is shipped
286
+     *
287
+     * @param string $appId the id of the app to check
288
+     * @return bool
289
+     *
290
+     * Check if an app that is installed is a shipped app or installed from the appstore.
291
+     */
292
+    public static function isShipped($appId) {
293
+        return \OC::$server->getAppManager()->isShipped($appId);
294
+    }
295
+
296
+    /**
297
+     * get all enabled apps
298
+     */
299
+    protected static $enabledAppsCache = array();
300
+
301
+    /**
302
+     * Returns apps enabled for the current user.
303
+     *
304
+     * @param bool $forceRefresh whether to refresh the cache
305
+     * @param bool $all whether to return apps for all users, not only the
306
+     * currently logged in one
307
+     * @return string[]
308
+     */
309
+    public static function getEnabledApps($forceRefresh = false, $all = false) {
310
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
311
+            return array();
312
+        }
313
+        // in incognito mode or when logged out, $user will be false,
314
+        // which is also the case during an upgrade
315
+        $appManager = \OC::$server->getAppManager();
316
+        if ($all) {
317
+            $user = null;
318
+        } else {
319
+            $user = \OC::$server->getUserSession()->getUser();
320
+        }
321
+
322
+        if (is_null($user)) {
323
+            $apps = $appManager->getInstalledApps();
324
+        } else {
325
+            $apps = $appManager->getEnabledAppsForUser($user);
326
+        }
327
+        $apps = array_filter($apps, function ($app) {
328
+            return $app !== 'files';//we add this manually
329
+        });
330
+        sort($apps);
331
+        array_unshift($apps, 'files');
332
+        return $apps;
333
+    }
334
+
335
+    /**
336
+     * checks whether or not an app is enabled
337
+     *
338
+     * @param string $app app
339
+     * @return bool
340
+     *
341
+     * This function checks whether or not an app is enabled.
342
+     */
343
+    public static function isEnabled($app) {
344
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
345
+    }
346
+
347
+    /**
348
+     * enables an app
349
+     *
350
+     * @param string $appId
351
+     * @param array $groups (optional) when set, only these groups will have access to the app
352
+     * @throws \Exception
353
+     * @return void
354
+     *
355
+     * This function set an app as enabled in appconfig.
356
+     */
357
+    public function enable($appId,
358
+                            $groups = null) {
359
+        self::$enabledAppsCache = []; // flush
360
+        $l = \OC::$server->getL10N('core');
361
+        $config = \OC::$server->getConfig();
362
+
363
+        // Check if app is already downloaded
364
+        $installer = new Installer(
365
+            \OC::$server->getAppFetcher(),
366
+            \OC::$server->getHTTPClientService(),
367
+            \OC::$server->getTempManager(),
368
+            \OC::$server->getLogger()
369
+        );
370
+        $isDownloaded = $installer->isDownloaded($appId);
371
+
372
+        if(!$isDownloaded) {
373
+            $installer->downloadApp($appId);
374
+        }
375
+
376
+        if (!Installer::isInstalled($appId)) {
377
+            $appId = self::installApp(
378
+                $appId,
379
+                $config,
380
+                $l
381
+            );
382
+            $appPath = self::getAppPath($appId);
383
+            self::registerAutoloading($appId, $appPath);
384
+            $installer->installApp($appId);
385
+        } else {
386
+            // check for required dependencies
387
+            $info = self::getAppInfo($appId);
388
+            self::checkAppDependencies($config, $l, $info);
389
+            $appPath = self::getAppPath($appId);
390
+            self::registerAutoloading($appId, $appPath);
391
+            $installer->installApp($appId);
392
+        }
393
+
394
+        $appManager = \OC::$server->getAppManager();
395
+        if (!is_null($groups)) {
396
+            $groupManager = \OC::$server->getGroupManager();
397
+            $groupsList = [];
398
+            foreach ($groups as $group) {
399
+                $groupItem = $groupManager->get($group);
400
+                if ($groupItem instanceof \OCP\IGroup) {
401
+                    $groupsList[] = $groupManager->get($group);
402
+                }
403
+            }
404
+            $appManager->enableAppForGroups($appId, $groupsList);
405
+        } else {
406
+            $appManager->enableApp($appId);
407
+        }
408
+
409
+        $info = self::getAppInfo($appId);
410
+        if(isset($info['settings']) && is_array($info['settings'])) {
411
+            $appPath = self::getAppPath($appId);
412
+            self::registerAutoloading($appId, $appPath);
413
+            \OC::$server->getSettingsManager()->setupSettings($info['settings']);
414
+        }
415
+    }
416
+
417
+    /**
418
+     * @param string $app
419
+     * @return bool
420
+     */
421
+    public static function removeApp($app) {
422
+        if (self::isShipped($app)) {
423
+            return false;
424
+        }
425
+
426
+        $installer = new Installer(
427
+            \OC::$server->getAppFetcher(),
428
+            \OC::$server->getHTTPClientService(),
429
+            \OC::$server->getTempManager(),
430
+            \OC::$server->getLogger()
431
+        );
432
+        return $installer->removeApp($app);
433
+    }
434
+
435
+    /**
436
+     * This function set an app as disabled in appconfig.
437
+     *
438
+     * @param string $app app
439
+     * @throws Exception
440
+     */
441
+    public static function disable($app) {
442
+        // flush
443
+        self::$enabledAppsCache = array();
444
+
445
+        // run uninstall steps
446
+        $appData = OC_App::getAppInfo($app);
447
+        if (!is_null($appData)) {
448
+            OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
449
+        }
450
+
451
+        // emit disable hook - needed anymore ?
452
+        \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
453
+
454
+        // finally disable it
455
+        $appManager = \OC::$server->getAppManager();
456
+        $appManager->disableApp($app);
457
+    }
458
+
459
+    /**
460
+     * Returns the Settings Navigation
461
+     *
462
+     * @return string[]
463
+     *
464
+     * This function returns an array containing all settings pages added. The
465
+     * entries are sorted by the key 'order' ascending.
466
+     */
467
+    public static function getSettingsNavigation() {
468
+        $l = \OC::$server->getL10N('lib');
469
+        $urlGenerator = \OC::$server->getURLGenerator();
470
+
471
+        $settings = array();
472
+        // by default, settings only contain the help menu
473
+        if (\OC::$server->getSystemConfig()->getValue('knowledgebaseenabled', true)) {
474
+            $settings = array(
475
+                array(
476
+                    "id" => "help",
477
+                    "order" => 4,
478
+                    "href" => $urlGenerator->linkToRoute('settings_help'),
479
+                    "name" => $l->t("Help"),
480
+                    "icon" => $urlGenerator->imagePath("settings", "help.svg")
481
+                )
482
+            );
483
+        }
484
+
485
+        // if the user is logged-in
486
+        if (\OC::$server->getUserSession()->isLoggedIn()) {
487
+            // personal menu
488
+            $settings[] = array(
489
+                "id" => "personal",
490
+                "order" => 1,
491
+                "href" => $urlGenerator->linkToRoute('settings_personal'),
492
+                "name" => $l->t("Personal"),
493
+                "icon" => $urlGenerator->imagePath("settings", "personal.svg")
494
+            );
495
+
496
+            //SubAdmins are also allowed to access user management
497
+            $userObject = \OC::$server->getUserSession()->getUser();
498
+            $isSubAdmin = false;
499
+            if($userObject !== null) {
500
+                $isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
501
+            }
502
+            if ($isSubAdmin) {
503
+                // admin users menu
504
+                $settings[] = array(
505
+                    "id" => "core_users",
506
+                    "order" => 3,
507
+                    "href" => $urlGenerator->linkToRoute('settings_users'),
508
+                    "name" => $l->t("Users"),
509
+                    "icon" => $urlGenerator->imagePath("settings", "users.svg")
510
+                );
511
+            }
512
+
513
+            // if the user is an admin
514
+            if (OC_User::isAdminUser(OC_User::getUser())) {
515
+                // admin settings
516
+                $settings[] = array(
517
+                    "id" => "admin",
518
+                    "order" => 2,
519
+                    "href" => $urlGenerator->linkToRoute('settings.AdminSettings.index'),
520
+                    "name" => $l->t("Admin"),
521
+                    "icon" => $urlGenerator->imagePath("settings", "admin.svg")
522
+                );
523
+            }
524
+        }
525
+
526
+        $navigation = self::proceedNavigation($settings);
527
+        return $navigation;
528
+    }
529
+
530
+    // This is private as well. It simply works, so don't ask for more details
531
+    private static function proceedNavigation($list) {
532
+        $activeApp = OC::$server->getNavigationManager()->getActiveEntry();
533
+        foreach ($list as &$navEntry) {
534
+            if ($navEntry['id'] == $activeApp) {
535
+                $navEntry['active'] = true;
536
+            } else {
537
+                $navEntry['active'] = false;
538
+            }
539
+        }
540
+        unset($navEntry);
541
+
542
+        usort($list, function($a, $b) {
543
+            if (isset($a['order']) && isset($b['order'])) {
544
+                return ($a['order'] < $b['order']) ? -1 : 1;
545
+            } else if (isset($a['order']) || isset($b['order'])) {
546
+                return isset($a['order']) ? -1 : 1;
547
+            } else {
548
+                return ($a['name'] < $b['name']) ? -1 : 1;
549
+            }
550
+        });
551
+
552
+        return $list;
553
+    }
554
+
555
+    /**
556
+     * Get the path where to install apps
557
+     *
558
+     * @return string|false
559
+     */
560
+    public static function getInstallPath() {
561
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
562
+            return false;
563
+        }
564
+
565
+        foreach (OC::$APPSROOTS as $dir) {
566
+            if (isset($dir['writable']) && $dir['writable'] === true) {
567
+                return $dir['path'];
568
+            }
569
+        }
570
+
571
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
572
+        return null;
573
+    }
574
+
575
+
576
+    /**
577
+     * search for an app in all app-directories
578
+     *
579
+     * @param string $appId
580
+     * @return false|string
581
+     */
582
+    public static function findAppInDirectories($appId) {
583
+        $sanitizedAppId = self::cleanAppId($appId);
584
+        if($sanitizedAppId !== $appId) {
585
+            return false;
586
+        }
587
+        static $app_dir = array();
588
+
589
+        if (isset($app_dir[$appId])) {
590
+            return $app_dir[$appId];
591
+        }
592
+
593
+        $possibleApps = array();
594
+        foreach (OC::$APPSROOTS as $dir) {
595
+            if (file_exists($dir['path'] . '/' . $appId)) {
596
+                $possibleApps[] = $dir;
597
+            }
598
+        }
599
+
600
+        if (empty($possibleApps)) {
601
+            return false;
602
+        } elseif (count($possibleApps) === 1) {
603
+            $dir = array_shift($possibleApps);
604
+            $app_dir[$appId] = $dir;
605
+            return $dir;
606
+        } else {
607
+            $versionToLoad = array();
608
+            foreach ($possibleApps as $possibleApp) {
609
+                $version = self::getAppVersionByPath($possibleApp['path']);
610
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
611
+                    $versionToLoad = array(
612
+                        'dir' => $possibleApp,
613
+                        'version' => $version,
614
+                    );
615
+                }
616
+            }
617
+            $app_dir[$appId] = $versionToLoad['dir'];
618
+            return $versionToLoad['dir'];
619
+            //TODO - write test
620
+        }
621
+    }
622
+
623
+    /**
624
+     * Get the directory for the given app.
625
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
626
+     *
627
+     * @param string $appId
628
+     * @return string|false
629
+     */
630
+    public static function getAppPath($appId) {
631
+        if ($appId === null || trim($appId) === '') {
632
+            return false;
633
+        }
634
+
635
+        if (($dir = self::findAppInDirectories($appId)) != false) {
636
+            return $dir['path'] . '/' . $appId;
637
+        }
638
+        return false;
639
+    }
640
+
641
+    /**
642
+     * Get the path for the given app on the access
643
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
644
+     *
645
+     * @param string $appId
646
+     * @return string|false
647
+     */
648
+    public static function getAppWebPath($appId) {
649
+        if (($dir = self::findAppInDirectories($appId)) != false) {
650
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
651
+        }
652
+        return false;
653
+    }
654
+
655
+    /**
656
+     * get the last version of the app from appinfo/info.xml
657
+     *
658
+     * @param string $appId
659
+     * @param bool $useCache
660
+     * @return string
661
+     */
662
+    public static function getAppVersion($appId, $useCache = true) {
663
+        if($useCache && isset(self::$appVersion[$appId])) {
664
+            return self::$appVersion[$appId];
665
+        }
666
+
667
+        $file = self::getAppPath($appId);
668
+        self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
669
+        return self::$appVersion[$appId];
670
+    }
671
+
672
+    /**
673
+     * get app's version based on it's path
674
+     *
675
+     * @param string $path
676
+     * @return string
677
+     */
678
+    public static function getAppVersionByPath($path) {
679
+        $infoFile = $path . '/appinfo/info.xml';
680
+        $appData = self::getAppInfo($infoFile, true);
681
+        return isset($appData['version']) ? $appData['version'] : '';
682
+    }
683
+
684
+
685
+    /**
686
+     * Read all app metadata from the info.xml file
687
+     *
688
+     * @param string $appId id of the app or the path of the info.xml file
689
+     * @param bool $path
690
+     * @param string $lang
691
+     * @return array|null
692
+     * @note all data is read from info.xml, not just pre-defined fields
693
+     */
694
+    public static function getAppInfo($appId, $path = false, $lang = null) {
695
+        if ($path) {
696
+            $file = $appId;
697
+        } else {
698
+            if ($lang === null && isset(self::$appInfo[$appId])) {
699
+                return self::$appInfo[$appId];
700
+            }
701
+            $appPath = self::getAppPath($appId);
702
+            if($appPath === false) {
703
+                return null;
704
+            }
705
+            $file = $appPath . '/appinfo/info.xml';
706
+        }
707
+
708
+        $parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
709
+        $data = $parser->parse($file);
710
+
711
+        if (is_array($data)) {
712
+            $data = OC_App::parseAppInfo($data, $lang);
713
+        }
714
+        if(isset($data['ocsid'])) {
715
+            $storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
716
+            if($storedId !== '' && $storedId !== $data['ocsid']) {
717
+                $data['ocsid'] = $storedId;
718
+            }
719
+        }
720
+
721
+        if ($lang === null) {
722
+            self::$appInfo[$appId] = $data;
723
+        }
724
+
725
+        return $data;
726
+    }
727
+
728
+    /**
729
+     * Returns the navigation
730
+     *
731
+     * @return array
732
+     *
733
+     * This function returns an array containing all entries added. The
734
+     * entries are sorted by the key 'order' ascending. Additional to the keys
735
+     * given for each app the following keys exist:
736
+     *   - active: boolean, signals if the user is on this navigation entry
737
+     */
738
+    public static function getNavigation() {
739
+        $entries = OC::$server->getNavigationManager()->getAll();
740
+        $navigation = self::proceedNavigation($entries);
741
+        return $navigation;
742
+    }
743
+
744
+    /**
745
+     * get the id of loaded app
746
+     *
747
+     * @return string
748
+     */
749
+    public static function getCurrentApp() {
750
+        $request = \OC::$server->getRequest();
751
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
752
+        $topFolder = substr($script, 0, strpos($script, '/'));
753
+        if (empty($topFolder)) {
754
+            $path_info = $request->getPathInfo();
755
+            if ($path_info) {
756
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
757
+            }
758
+        }
759
+        if ($topFolder == 'apps') {
760
+            $length = strlen($topFolder);
761
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
762
+        } else {
763
+            return $topFolder;
764
+        }
765
+    }
766
+
767
+    /**
768
+     * @param string $type
769
+     * @return array
770
+     */
771
+    public static function getForms($type) {
772
+        $forms = array();
773
+        switch ($type) {
774
+            case 'admin':
775
+                $source = self::$adminForms;
776
+                break;
777
+            case 'personal':
778
+                $source = self::$personalForms;
779
+                break;
780
+            default:
781
+                return array();
782
+        }
783
+        foreach ($source as $form) {
784
+            $forms[] = include $form;
785
+        }
786
+        return $forms;
787
+    }
788
+
789
+    /**
790
+     * register an admin form to be shown
791
+     *
792
+     * @param string $app
793
+     * @param string $page
794
+     */
795
+    public static function registerAdmin($app, $page) {
796
+        self::$adminForms[] = $app . '/' . $page . '.php';
797
+    }
798
+
799
+    /**
800
+     * register a personal form to be shown
801
+     * @param string $app
802
+     * @param string $page
803
+     */
804
+    public static function registerPersonal($app, $page) {
805
+        self::$personalForms[] = $app . '/' . $page . '.php';
806
+    }
807
+
808
+    /**
809
+     * @param array $entry
810
+     */
811
+    public static function registerLogIn(array $entry) {
812
+        self::$altLogin[] = $entry;
813
+    }
814
+
815
+    /**
816
+     * @return array
817
+     */
818
+    public static function getAlternativeLogIns() {
819
+        return self::$altLogin;
820
+    }
821
+
822
+    /**
823
+     * get a list of all apps in the apps folder
824
+     *
825
+     * @return array an array of app names (string IDs)
826
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
827
+     */
828
+    public static function getAllApps() {
829
+
830
+        $apps = array();
831
+
832
+        foreach (OC::$APPSROOTS as $apps_dir) {
833
+            if (!is_readable($apps_dir['path'])) {
834
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
835
+                continue;
836
+            }
837
+            $dh = opendir($apps_dir['path']);
838
+
839
+            if (is_resource($dh)) {
840
+                while (($file = readdir($dh)) !== false) {
841
+
842
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
843
+
844
+                        $apps[] = $file;
845
+                    }
846
+                }
847
+            }
848
+        }
849
+
850
+        return $apps;
851
+    }
852
+
853
+    /**
854
+     * List all apps, this is used in apps.php
855
+     *
856
+     * @return array
857
+     */
858
+    public function listAllApps() {
859
+        $installedApps = OC_App::getAllApps();
860
+
861
+        //we don't want to show configuration for these
862
+        $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
863
+        $appList = array();
864
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
865
+        $urlGenerator = \OC::$server->getURLGenerator();
866
+
867
+        foreach ($installedApps as $app) {
868
+            if (array_search($app, $blacklist) === false) {
869
+
870
+                $info = OC_App::getAppInfo($app, false, $langCode);
871
+                if (!is_array($info)) {
872
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
873
+                    continue;
874
+                }
875
+
876
+                if (!isset($info['name'])) {
877
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
878
+                    continue;
879
+                }
880
+
881
+                $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
882
+                $info['groups'] = null;
883
+                if ($enabled === 'yes') {
884
+                    $active = true;
885
+                } else if ($enabled === 'no') {
886
+                    $active = false;
887
+                } else {
888
+                    $active = true;
889
+                    $info['groups'] = $enabled;
890
+                }
891
+
892
+                $info['active'] = $active;
893
+
894
+                if (self::isShipped($app)) {
895
+                    $info['internal'] = true;
896
+                    $info['level'] = self::officialApp;
897
+                    $info['removable'] = false;
898
+                } else {
899
+                    $info['internal'] = false;
900
+                    $info['removable'] = true;
901
+                }
902
+
903
+                $appPath = self::getAppPath($app);
904
+                if($appPath !== false) {
905
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
906
+                    if (file_exists($appIcon)) {
907
+                        $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
908
+                        $info['previewAsIcon'] = true;
909
+                    } else {
910
+                        $appIcon = $appPath . '/img/app.svg';
911
+                        if (file_exists($appIcon)) {
912
+                            $info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
913
+                            $info['previewAsIcon'] = true;
914
+                        }
915
+                    }
916
+                }
917
+                // fix documentation
918
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
919
+                    foreach ($info['documentation'] as $key => $url) {
920
+                        // If it is not an absolute URL we assume it is a key
921
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
922
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
923
+                            $url = $urlGenerator->linkToDocs($url);
924
+                        }
925
+
926
+                        $info['documentation'][$key] = $url;
927
+                    }
928
+                }
929
+
930
+                $info['version'] = OC_App::getAppVersion($app);
931
+                $appList[] = $info;
932
+            }
933
+        }
934
+
935
+        return $appList;
936
+    }
937
+
938
+    /**
939
+     * Returns the internal app ID or false
940
+     * @param string $ocsID
941
+     * @return string|false
942
+     */
943
+    public static function getInternalAppIdByOcs($ocsID) {
944
+        if(is_numeric($ocsID)) {
945
+            $idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
946
+            if(array_search($ocsID, $idArray)) {
947
+                return array_search($ocsID, $idArray);
948
+            }
949
+        }
950
+        return false;
951
+    }
952
+
953
+    public static function shouldUpgrade($app) {
954
+        $versions = self::getAppVersions();
955
+        $currentVersion = OC_App::getAppVersion($app);
956
+        if ($currentVersion && isset($versions[$app])) {
957
+            $installedVersion = $versions[$app];
958
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
959
+                return true;
960
+            }
961
+        }
962
+        return false;
963
+    }
964
+
965
+    /**
966
+     * Adjust the number of version parts of $version1 to match
967
+     * the number of version parts of $version2.
968
+     *
969
+     * @param string $version1 version to adjust
970
+     * @param string $version2 version to take the number of parts from
971
+     * @return string shortened $version1
972
+     */
973
+    private static function adjustVersionParts($version1, $version2) {
974
+        $version1 = explode('.', $version1);
975
+        $version2 = explode('.', $version2);
976
+        // reduce $version1 to match the number of parts in $version2
977
+        while (count($version1) > count($version2)) {
978
+            array_pop($version1);
979
+        }
980
+        // if $version1 does not have enough parts, add some
981
+        while (count($version1) < count($version2)) {
982
+            $version1[] = '0';
983
+        }
984
+        return implode('.', $version1);
985
+    }
986
+
987
+    /**
988
+     * Check whether the current ownCloud version matches the given
989
+     * application's version requirements.
990
+     *
991
+     * The comparison is made based on the number of parts that the
992
+     * app info version has. For example for ownCloud 6.0.3 if the
993
+     * app info version is expecting version 6.0, the comparison is
994
+     * made on the first two parts of the ownCloud version.
995
+     * This means that it's possible to specify "requiremin" => 6
996
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
997
+     *
998
+     * @param string $ocVersion ownCloud version to check against
999
+     * @param array $appInfo app info (from xml)
1000
+     *
1001
+     * @return boolean true if compatible, otherwise false
1002
+     */
1003
+    public static function isAppCompatible($ocVersion, $appInfo) {
1004
+        $requireMin = '';
1005
+        $requireMax = '';
1006
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
1007
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
1008
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
1009
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
1010
+        } else if (isset($appInfo['requiremin'])) {
1011
+            $requireMin = $appInfo['requiremin'];
1012
+        } else if (isset($appInfo['require'])) {
1013
+            $requireMin = $appInfo['require'];
1014
+        }
1015
+
1016
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
1017
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
1018
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
1019
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
1020
+        } else if (isset($appInfo['requiremax'])) {
1021
+            $requireMax = $appInfo['requiremax'];
1022
+        }
1023
+
1024
+        if (is_array($ocVersion)) {
1025
+            $ocVersion = implode('.', $ocVersion);
1026
+        }
1027
+
1028
+        if (!empty($requireMin)
1029
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
1030
+        ) {
1031
+
1032
+            return false;
1033
+        }
1034
+
1035
+        if (!empty($requireMax)
1036
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
1037
+        ) {
1038
+            return false;
1039
+        }
1040
+
1041
+        return true;
1042
+    }
1043
+
1044
+    /**
1045
+     * get the installed version of all apps
1046
+     */
1047
+    public static function getAppVersions() {
1048
+        static $versions;
1049
+
1050
+        if(!$versions) {
1051
+            $appConfig = \OC::$server->getAppConfig();
1052
+            $versions = $appConfig->getValues(false, 'installed_version');
1053
+        }
1054
+        return $versions;
1055
+    }
1056
+
1057
+    /**
1058
+     * @param string $app
1059
+     * @param \OCP\IConfig $config
1060
+     * @param \OCP\IL10N $l
1061
+     * @return bool
1062
+     *
1063
+     * @throws Exception if app is not compatible with this version of ownCloud
1064
+     * @throws Exception if no app-name was specified
1065
+     */
1066
+    public function installApp($app,
1067
+                                \OCP\IConfig $config,
1068
+                                \OCP\IL10N $l) {
1069
+        if ($app !== false) {
1070
+            // check if the app is compatible with this version of ownCloud
1071
+            $info = self::getAppInfo($app);
1072
+            if(!is_array($info)) {
1073
+                throw new \Exception(
1074
+                    $l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1075
+                        [$info['name']]
1076
+                    )
1077
+                );
1078
+            }
1079
+
1080
+            $version = \OCP\Util::getVersion();
1081
+            if (!self::isAppCompatible($version, $info)) {
1082
+                throw new \Exception(
1083
+                    $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
1084
+                        array($info['name'])
1085
+                    )
1086
+                );
1087
+            }
1088
+
1089
+            // check for required dependencies
1090
+            self::checkAppDependencies($config, $l, $info);
1091
+
1092
+            $config->setAppValue($app, 'enabled', 'yes');
1093
+            if (isset($appData['id'])) {
1094
+                $config->setAppValue($app, 'ocsid', $appData['id']);
1095
+            }
1096
+
1097
+            if(isset($info['settings']) && is_array($info['settings'])) {
1098
+                $appPath = self::getAppPath($app);
1099
+                self::registerAutoloading($app, $appPath);
1100
+                \OC::$server->getSettingsManager()->setupSettings($info['settings']);
1101
+            }
1102
+
1103
+            \OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1104
+        } else {
1105
+            if(empty($appName) ) {
1106
+                throw new \Exception($l->t("No app name specified"));
1107
+            } else {
1108
+                throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1109
+            }
1110
+        }
1111
+
1112
+        return $app;
1113
+    }
1114
+
1115
+    /**
1116
+     * update the database for the app and call the update script
1117
+     *
1118
+     * @param string $appId
1119
+     * @return bool
1120
+     */
1121
+    public static function updateApp($appId) {
1122
+        $appPath = self::getAppPath($appId);
1123
+        if($appPath === false) {
1124
+            return false;
1125
+        }
1126
+        $appData = self::getAppInfo($appId);
1127
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1128
+        if (file_exists($appPath . '/appinfo/database.xml')) {
1129
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1130
+        }
1131
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1132
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1133
+        unset(self::$appVersion[$appId]);
1134
+        // run upgrade code
1135
+        if (file_exists($appPath . '/appinfo/update.php')) {
1136
+            self::loadApp($appId);
1137
+            include $appPath . '/appinfo/update.php';
1138
+        }
1139
+        self::setupBackgroundJobs($appData['background-jobs']);
1140
+        if(isset($appData['settings']) && is_array($appData['settings'])) {
1141
+            $appPath = self::getAppPath($appId);
1142
+            self::registerAutoloading($appId, $appPath);
1143
+            \OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1144
+        }
1145
+
1146
+        //set remote/public handlers
1147
+        if (array_key_exists('ocsid', $appData)) {
1148
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1149
+        } elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1150
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1151
+        }
1152
+        foreach ($appData['remote'] as $name => $path) {
1153
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1154
+        }
1155
+        foreach ($appData['public'] as $name => $path) {
1156
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1157
+        }
1158
+
1159
+        self::setAppTypes($appId);
1160
+
1161
+        $version = \OC_App::getAppVersion($appId);
1162
+        \OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1163
+
1164
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1165
+            ManagerEvent::EVENT_APP_UPDATE, $appId
1166
+        ));
1167
+
1168
+        return true;
1169
+    }
1170
+
1171
+    /**
1172
+     * @param string $appId
1173
+     * @param string[] $steps
1174
+     * @throws \OC\NeedsUpdateException
1175
+     */
1176
+    public static function executeRepairSteps($appId, array $steps) {
1177
+        if (empty($steps)) {
1178
+            return;
1179
+        }
1180
+        // load the app
1181
+        self::loadApp($appId);
1182
+
1183
+        $dispatcher = OC::$server->getEventDispatcher();
1184
+
1185
+        // load the steps
1186
+        $r = new Repair([], $dispatcher);
1187
+        foreach ($steps as $step) {
1188
+            try {
1189
+                $r->addStep($step);
1190
+            } catch (Exception $ex) {
1191
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1192
+                \OC::$server->getLogger()->logException($ex);
1193
+            }
1194
+        }
1195
+        // run the steps
1196
+        $r->run();
1197
+    }
1198
+
1199
+    public static function setupBackgroundJobs(array $jobs) {
1200
+        $queue = \OC::$server->getJobList();
1201
+        foreach ($jobs as $job) {
1202
+            $queue->add($job);
1203
+        }
1204
+    }
1205
+
1206
+    /**
1207
+     * @param string $appId
1208
+     * @param string[] $steps
1209
+     */
1210
+    private static function setupLiveMigrations($appId, array $steps) {
1211
+        $queue = \OC::$server->getJobList();
1212
+        foreach ($steps as $step) {
1213
+            $queue->add('OC\Migration\BackgroundRepair', [
1214
+                'app' => $appId,
1215
+                'step' => $step]);
1216
+        }
1217
+    }
1218
+
1219
+    /**
1220
+     * @param string $appId
1221
+     * @return \OC\Files\View|false
1222
+     */
1223
+    public static function getStorage($appId) {
1224
+        if (OC_App::isEnabled($appId)) { //sanity check
1225
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
1226
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1227
+                if (!$view->file_exists($appId)) {
1228
+                    $view->mkdir($appId);
1229
+                }
1230
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1231
+            } else {
1232
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1233
+                return false;
1234
+            }
1235
+        } else {
1236
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1237
+            return false;
1238
+        }
1239
+    }
1240
+
1241
+    protected static function findBestL10NOption($options, $lang) {
1242
+        $fallback = $similarLangFallback = $englishFallback = false;
1243
+
1244
+        $lang = strtolower($lang);
1245
+        $similarLang = $lang;
1246
+        if (strpos($similarLang, '_')) {
1247
+            // For "de_DE" we want to find "de" and the other way around
1248
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1249
+        }
1250
+
1251
+        foreach ($options as $option) {
1252
+            if (is_array($option)) {
1253
+                if ($fallback === false) {
1254
+                    $fallback = $option['@value'];
1255
+                }
1256
+
1257
+                if (!isset($option['@attributes']['lang'])) {
1258
+                    continue;
1259
+                }
1260
+
1261
+                $attributeLang = strtolower($option['@attributes']['lang']);
1262
+                if ($attributeLang === $lang) {
1263
+                    return $option['@value'];
1264
+                }
1265
+
1266
+                if ($attributeLang === $similarLang) {
1267
+                    $similarLangFallback = $option['@value'];
1268
+                } else if (strpos($attributeLang, $similarLang . '_') === 0) {
1269
+                    if ($similarLangFallback === false) {
1270
+                        $similarLangFallback =  $option['@value'];
1271
+                    }
1272
+                }
1273
+            } else {
1274
+                $englishFallback = $option;
1275
+            }
1276
+        }
1277
+
1278
+        if ($similarLangFallback !== false) {
1279
+            return $similarLangFallback;
1280
+        } else if ($englishFallback !== false) {
1281
+            return $englishFallback;
1282
+        }
1283
+        return (string) $fallback;
1284
+    }
1285
+
1286
+    /**
1287
+     * parses the app data array and enhanced the 'description' value
1288
+     *
1289
+     * @param array $data the app data
1290
+     * @param string $lang
1291
+     * @return array improved app data
1292
+     */
1293
+    public static function parseAppInfo(array $data, $lang = null) {
1294
+
1295
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1296
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1297
+        }
1298
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1299
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1300
+        }
1301
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1302
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1303
+        } else if (isset($data['description']) && is_string($data['description'])) {
1304
+            $data['description'] = trim($data['description']);
1305
+        } else  {
1306
+            $data['description'] = '';
1307
+        }
1308
+
1309
+        return $data;
1310
+    }
1311
+
1312
+    /**
1313
+     * @param \OCP\IConfig $config
1314
+     * @param \OCP\IL10N $l
1315
+     * @param array $info
1316
+     * @throws \Exception
1317
+     */
1318
+    protected static function checkAppDependencies($config, $l, $info) {
1319
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1320
+        $missing = $dependencyAnalyzer->analyze($info);
1321
+        if (!empty($missing)) {
1322
+            $missingMsg = join(PHP_EOL, $missing);
1323
+            throw new \Exception(
1324
+                $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1325
+                    [$info['name'], $missingMsg]
1326
+                )
1327
+            );
1328
+        }
1329
+    }
1330 1330
 }
Please login to merge, or discard this patch.
Spacing   +59 added lines, -59 removed lines patch added patch discarded remove patch
@@ -111,9 +111,9 @@  discard block
 block discarded – undo
111 111
 		$apps = self::getEnabledApps();
112 112
 
113 113
 		// Add each apps' folder as allowed class path
114
-		foreach($apps as $app) {
114
+		foreach ($apps as $app) {
115 115
 			$path = self::getAppPath($app);
116
-			if($path !== false) {
116
+			if ($path !== false) {
117 117
 				self::registerAutoloading($app, $path);
118 118
 			}
119 119
 		}
@@ -138,15 +138,15 @@  discard block
 block discarded – undo
138 138
 	public static function loadApp($app) {
139 139
 		self::$loadedApps[] = $app;
140 140
 		$appPath = self::getAppPath($app);
141
-		if($appPath === false) {
141
+		if ($appPath === false) {
142 142
 			return;
143 143
 		}
144 144
 
145 145
 		// in case someone calls loadApp() directly
146 146
 		self::registerAutoloading($app, $appPath);
147 147
 
148
-		if (is_file($appPath . '/appinfo/app.php')) {
149
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
148
+		if (is_file($appPath.'/appinfo/app.php')) {
149
+			\OC::$server->getEventLogger()->start('load_app_'.$app, 'Load app: '.$app);
150 150
 			self::requireAppFile($app);
151 151
 			if (self::isType($app, array('authentication'))) {
152 152
 				// since authentication apps affect the "is app enabled for group" check,
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
 				// enabled for groups
156 156
 				self::$enabledAppsCache = array();
157 157
 			}
158
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
158
+			\OC::$server->getEventLogger()->end('load_app_'.$app);
159 159
 		}
160 160
 
161 161
 		$info = self::getAppInfo($app);
@@ -182,16 +182,16 @@  discard block
 block discarded – undo
182 182
 	 * @param string $path
183 183
 	 */
184 184
 	public static function registerAutoloading($app, $path) {
185
-		$key = $app . '-' . $path;
186
-		if(isset(self::$alreadyRegistered[$key])) {
185
+		$key = $app.'-'.$path;
186
+		if (isset(self::$alreadyRegistered[$key])) {
187 187
 			return;
188 188
 		}
189 189
 		self::$alreadyRegistered[$key] = true;
190 190
 		// Register on PSR-4 composer autoloader
191 191
 		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
192
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
192
+		\OC::$composerAutoloader->addPsr4($appNamespace.'\\', $path.'/lib/', true);
193 193
 		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
194
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
194
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\Tests\\', $path.'/tests/', true);
195 195
 		}
196 196
 
197 197
 		// Register on legacy autoloader
@@ -206,7 +206,7 @@  discard block
 block discarded – undo
206 206
 	private static function requireAppFile($app) {
207 207
 		try {
208 208
 			// encapsulated here to avoid variable scope conflicts
209
-			require_once $app . '/appinfo/app.php';
209
+			require_once $app.'/appinfo/app.php';
210 210
 		} catch (Error $ex) {
211 211
 			\OC::$server->getLogger()->logException($ex);
212 212
 			$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
@@ -260,7 +260,7 @@  discard block
 block discarded – undo
260 260
 	 */
261 261
 	public static function setAppTypes($app) {
262 262
 		$appData = self::getAppInfo($app);
263
-		if(!is_array($appData)) {
263
+		if (!is_array($appData)) {
264 264
 			return;
265 265
 		}
266 266
 
@@ -324,8 +324,8 @@  discard block
 block discarded – undo
324 324
 		} else {
325 325
 			$apps = $appManager->getEnabledAppsForUser($user);
326 326
 		}
327
-		$apps = array_filter($apps, function ($app) {
328
-			return $app !== 'files';//we add this manually
327
+		$apps = array_filter($apps, function($app) {
328
+			return $app !== 'files'; //we add this manually
329 329
 		});
330 330
 		sort($apps);
331 331
 		array_unshift($apps, 'files');
@@ -369,7 +369,7 @@  discard block
 block discarded – undo
369 369
 		);
370 370
 		$isDownloaded = $installer->isDownloaded($appId);
371 371
 
372
-		if(!$isDownloaded) {
372
+		if (!$isDownloaded) {
373 373
 			$installer->downloadApp($appId);
374 374
 		}
375 375
 
@@ -407,7 +407,7 @@  discard block
 block discarded – undo
407 407
 		}
408 408
 
409 409
 		$info = self::getAppInfo($appId);
410
-		if(isset($info['settings']) && is_array($info['settings'])) {
410
+		if (isset($info['settings']) && is_array($info['settings'])) {
411 411
 			$appPath = self::getAppPath($appId);
412 412
 			self::registerAutoloading($appId, $appPath);
413 413
 			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
@@ -496,7 +496,7 @@  discard block
 block discarded – undo
496 496
 			//SubAdmins are also allowed to access user management
497 497
 			$userObject = \OC::$server->getUserSession()->getUser();
498 498
 			$isSubAdmin = false;
499
-			if($userObject !== null) {
499
+			if ($userObject !== null) {
500 500
 				$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
501 501
 			}
502 502
 			if ($isSubAdmin) {
@@ -581,7 +581,7 @@  discard block
 block discarded – undo
581 581
 	 */
582 582
 	public static function findAppInDirectories($appId) {
583 583
 		$sanitizedAppId = self::cleanAppId($appId);
584
-		if($sanitizedAppId !== $appId) {
584
+		if ($sanitizedAppId !== $appId) {
585 585
 			return false;
586 586
 		}
587 587
 		static $app_dir = array();
@@ -592,7 +592,7 @@  discard block
 block discarded – undo
592 592
 
593 593
 		$possibleApps = array();
594 594
 		foreach (OC::$APPSROOTS as $dir) {
595
-			if (file_exists($dir['path'] . '/' . $appId)) {
595
+			if (file_exists($dir['path'].'/'.$appId)) {
596 596
 				$possibleApps[] = $dir;
597 597
 			}
598 598
 		}
@@ -633,7 +633,7 @@  discard block
 block discarded – undo
633 633
 		}
634 634
 
635 635
 		if (($dir = self::findAppInDirectories($appId)) != false) {
636
-			return $dir['path'] . '/' . $appId;
636
+			return $dir['path'].'/'.$appId;
637 637
 		}
638 638
 		return false;
639 639
 	}
@@ -647,7 +647,7 @@  discard block
 block discarded – undo
647 647
 	 */
648 648
 	public static function getAppWebPath($appId) {
649 649
 		if (($dir = self::findAppInDirectories($appId)) != false) {
650
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
650
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
651 651
 		}
652 652
 		return false;
653 653
 	}
@@ -660,7 +660,7 @@  discard block
 block discarded – undo
660 660
 	 * @return string
661 661
 	 */
662 662
 	public static function getAppVersion($appId, $useCache = true) {
663
-		if($useCache && isset(self::$appVersion[$appId])) {
663
+		if ($useCache && isset(self::$appVersion[$appId])) {
664 664
 			return self::$appVersion[$appId];
665 665
 		}
666 666
 
@@ -676,7 +676,7 @@  discard block
 block discarded – undo
676 676
 	 * @return string
677 677
 	 */
678 678
 	public static function getAppVersionByPath($path) {
679
-		$infoFile = $path . '/appinfo/info.xml';
679
+		$infoFile = $path.'/appinfo/info.xml';
680 680
 		$appData = self::getAppInfo($infoFile, true);
681 681
 		return isset($appData['version']) ? $appData['version'] : '';
682 682
 	}
@@ -699,10 +699,10 @@  discard block
 block discarded – undo
699 699
 				return self::$appInfo[$appId];
700 700
 			}
701 701
 			$appPath = self::getAppPath($appId);
702
-			if($appPath === false) {
702
+			if ($appPath === false) {
703 703
 				return null;
704 704
 			}
705
-			$file = $appPath . '/appinfo/info.xml';
705
+			$file = $appPath.'/appinfo/info.xml';
706 706
 		}
707 707
 
708 708
 		$parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
@@ -711,9 +711,9 @@  discard block
 block discarded – undo
711 711
 		if (is_array($data)) {
712 712
 			$data = OC_App::parseAppInfo($data, $lang);
713 713
 		}
714
-		if(isset($data['ocsid'])) {
714
+		if (isset($data['ocsid'])) {
715 715
 			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
716
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
716
+			if ($storedId !== '' && $storedId !== $data['ocsid']) {
717 717
 				$data['ocsid'] = $storedId;
718 718
 			}
719 719
 		}
@@ -793,7 +793,7 @@  discard block
 block discarded – undo
793 793
 	 * @param string $page
794 794
 	 */
795 795
 	public static function registerAdmin($app, $page) {
796
-		self::$adminForms[] = $app . '/' . $page . '.php';
796
+		self::$adminForms[] = $app.'/'.$page.'.php';
797 797
 	}
798 798
 
799 799
 	/**
@@ -802,7 +802,7 @@  discard block
 block discarded – undo
802 802
 	 * @param string $page
803 803
 	 */
804 804
 	public static function registerPersonal($app, $page) {
805
-		self::$personalForms[] = $app . '/' . $page . '.php';
805
+		self::$personalForms[] = $app.'/'.$page.'.php';
806 806
 	}
807 807
 
808 808
 	/**
@@ -831,7 +831,7 @@  discard block
 block discarded – undo
831 831
 
832 832
 		foreach (OC::$APPSROOTS as $apps_dir) {
833 833
 			if (!is_readable($apps_dir['path'])) {
834
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
834
+				\OCP\Util::writeLog('core', 'unable to read app folder : '.$apps_dir['path'], \OCP\Util::WARN);
835 835
 				continue;
836 836
 			}
837 837
 			$dh = opendir($apps_dir['path']);
@@ -839,7 +839,7 @@  discard block
 block discarded – undo
839 839
 			if (is_resource($dh)) {
840 840
 				while (($file = readdir($dh)) !== false) {
841 841
 
842
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
842
+					if ($file[0] != '.' and is_dir($apps_dir['path'].'/'.$file) and is_file($apps_dir['path'].'/'.$file.'/appinfo/info.xml')) {
843 843
 
844 844
 						$apps[] = $file;
845 845
 					}
@@ -869,12 +869,12 @@  discard block
 block discarded – undo
869 869
 
870 870
 				$info = OC_App::getAppInfo($app, false, $langCode);
871 871
 				if (!is_array($info)) {
872
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
872
+					\OCP\Util::writeLog('core', 'Could not read app info file for app "'.$app.'"', \OCP\Util::ERROR);
873 873
 					continue;
874 874
 				}
875 875
 
876 876
 				if (!isset($info['name'])) {
877
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
877
+					\OCP\Util::writeLog('core', 'App id "'.$app.'" has no name in appinfo', \OCP\Util::ERROR);
878 878
 					continue;
879 879
 				}
880 880
 
@@ -901,13 +901,13 @@  discard block
 block discarded – undo
901 901
 				}
902 902
 
903 903
 				$appPath = self::getAppPath($app);
904
-				if($appPath !== false) {
905
-					$appIcon = $appPath . '/img/' . $app . '.svg';
904
+				if ($appPath !== false) {
905
+					$appIcon = $appPath.'/img/'.$app.'.svg';
906 906
 					if (file_exists($appIcon)) {
907
-						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app . '.svg');
907
+						$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, $app.'.svg');
908 908
 						$info['previewAsIcon'] = true;
909 909
 					} else {
910
-						$appIcon = $appPath . '/img/app.svg';
910
+						$appIcon = $appPath.'/img/app.svg';
911 911
 						if (file_exists($appIcon)) {
912 912
 							$info['preview'] = \OC::$server->getURLGenerator()->imagePath($app, 'app.svg');
913 913
 							$info['previewAsIcon'] = true;
@@ -941,9 +941,9 @@  discard block
 block discarded – undo
941 941
 	 * @return string|false
942 942
 	 */
943 943
 	public static function getInternalAppIdByOcs($ocsID) {
944
-		if(is_numeric($ocsID)) {
944
+		if (is_numeric($ocsID)) {
945 945
 			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
946
-			if(array_search($ocsID, $idArray)) {
946
+			if (array_search($ocsID, $idArray)) {
947 947
 				return array_search($ocsID, $idArray);
948 948
 			}
949 949
 		}
@@ -1047,7 +1047,7 @@  discard block
 block discarded – undo
1047 1047
 	public static function getAppVersions() {
1048 1048
 		static $versions;
1049 1049
 
1050
-		if(!$versions) {
1050
+		if (!$versions) {
1051 1051
 			$appConfig = \OC::$server->getAppConfig();
1052 1052
 			$versions = $appConfig->getValues(false, 'installed_version');
1053 1053
 		}
@@ -1069,7 +1069,7 @@  discard block
 block discarded – undo
1069 1069
 		if ($app !== false) {
1070 1070
 			// check if the app is compatible with this version of ownCloud
1071 1071
 			$info = self::getAppInfo($app);
1072
-			if(!is_array($info)) {
1072
+			if (!is_array($info)) {
1073 1073
 				throw new \Exception(
1074 1074
 					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
1075 1075
 						[$info['name']]
@@ -1094,7 +1094,7 @@  discard block
 block discarded – undo
1094 1094
 				$config->setAppValue($app, 'ocsid', $appData['id']);
1095 1095
 			}
1096 1096
 
1097
-			if(isset($info['settings']) && is_array($info['settings'])) {
1097
+			if (isset($info['settings']) && is_array($info['settings'])) {
1098 1098
 				$appPath = self::getAppPath($app);
1099 1099
 				self::registerAutoloading($app, $appPath);
1100 1100
 				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
@@ -1102,7 +1102,7 @@  discard block
 block discarded – undo
1102 1102
 
1103 1103
 			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1104 1104
 		} else {
1105
-			if(empty($appName) ) {
1105
+			if (empty($appName)) {
1106 1106
 				throw new \Exception($l->t("No app name specified"));
1107 1107
 			} else {
1108 1108
 				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
@@ -1120,24 +1120,24 @@  discard block
 block discarded – undo
1120 1120
 	 */
1121 1121
 	public static function updateApp($appId) {
1122 1122
 		$appPath = self::getAppPath($appId);
1123
-		if($appPath === false) {
1123
+		if ($appPath === false) {
1124 1124
 			return false;
1125 1125
 		}
1126 1126
 		$appData = self::getAppInfo($appId);
1127 1127
 		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1128
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1129
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1128
+		if (file_exists($appPath.'/appinfo/database.xml')) {
1129
+			OC_DB::updateDbFromStructure($appPath.'/appinfo/database.xml');
1130 1130
 		}
1131 1131
 		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1132 1132
 		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1133 1133
 		unset(self::$appVersion[$appId]);
1134 1134
 		// run upgrade code
1135
-		if (file_exists($appPath . '/appinfo/update.php')) {
1135
+		if (file_exists($appPath.'/appinfo/update.php')) {
1136 1136
 			self::loadApp($appId);
1137
-			include $appPath . '/appinfo/update.php';
1137
+			include $appPath.'/appinfo/update.php';
1138 1138
 		}
1139 1139
 		self::setupBackgroundJobs($appData['background-jobs']);
1140
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1140
+		if (isset($appData['settings']) && is_array($appData['settings'])) {
1141 1141
 			$appPath = self::getAppPath($appId);
1142 1142
 			self::registerAutoloading($appId, $appPath);
1143 1143
 			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
@@ -1146,14 +1146,14 @@  discard block
 block discarded – undo
1146 1146
 		//set remote/public handlers
1147 1147
 		if (array_key_exists('ocsid', $appData)) {
1148 1148
 			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1149
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1149
+		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1150 1150
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1151 1151
 		}
1152 1152
 		foreach ($appData['remote'] as $name => $path) {
1153
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1153
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
1154 1154
 		}
1155 1155
 		foreach ($appData['public'] as $name => $path) {
1156
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1156
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
1157 1157
 		}
1158 1158
 
1159 1159
 		self::setAppTypes($appId);
@@ -1223,17 +1223,17 @@  discard block
 block discarded – undo
1223 1223
 	public static function getStorage($appId) {
1224 1224
 		if (OC_App::isEnabled($appId)) { //sanity check
1225 1225
 			if (\OC::$server->getUserSession()->isLoggedIn()) {
1226
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1226
+				$view = new \OC\Files\View('/'.OC_User::getUser());
1227 1227
 				if (!$view->file_exists($appId)) {
1228 1228
 					$view->mkdir($appId);
1229 1229
 				}
1230
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1230
+				return new \OC\Files\View('/'.OC_User::getUser().'/'.$appId);
1231 1231
 			} else {
1232
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1232
+				\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.', user not logged in', \OCP\Util::ERROR);
1233 1233
 				return false;
1234 1234
 			}
1235 1235
 		} else {
1236
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1236
+			\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.' not enabled', \OCP\Util::ERROR);
1237 1237
 			return false;
1238 1238
 		}
1239 1239
 	}
@@ -1265,9 +1265,9 @@  discard block
 block discarded – undo
1265 1265
 
1266 1266
 				if ($attributeLang === $similarLang) {
1267 1267
 					$similarLangFallback = $option['@value'];
1268
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1268
+				} else if (strpos($attributeLang, $similarLang.'_') === 0) {
1269 1269
 					if ($similarLangFallback === false) {
1270
-						$similarLangFallback =  $option['@value'];
1270
+						$similarLangFallback = $option['@value'];
1271 1271
 					}
1272 1272
 				}
1273 1273
 			} else {
@@ -1302,7 +1302,7 @@  discard block
 block discarded – undo
1302 1302
 			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1303 1303
 		} else if (isset($data['description']) && is_string($data['description'])) {
1304 1304
 			$data['description'] = trim($data['description']);
1305
-		} else  {
1305
+		} else {
1306 1306
 			$data['description'] = '';
1307 1307
 		}
1308 1308
 
Please login to merge, or discard this patch.
lib/private/L10N/Factory.php 3 patches
Doc Comments   +5 added lines patch added patch discarded remove patch
@@ -318,6 +318,11 @@
 block discarded – undo
318 318
 	 */
319 319
 	// FIXME This method is only public, until OC_L10N does not need it anymore,
320 320
 	// FIXME This is also the reason, why it is not in the public interface
321
+
322
+	/**
323
+	 * @param string $app
324
+	 * @param string $lang
325
+	 */
321 326
 	public function getL10nFilesForApp($app, $lang) {
322 327
 		$languageFiles = [];
323 328
 
Please login to merge, or discard this patch.
Indentation   +387 added lines, -387 removed lines patch added patch discarded remove patch
@@ -40,391 +40,391 @@
 block discarded – undo
40 40
  */
41 41
 class Factory implements IFactory {
42 42
 
43
-	/** @var string */
44
-	protected $requestLanguage = '';
45
-
46
-	/**
47
-	 * cached instances
48
-	 * @var array Structure: Lang => App => \OCP\IL10N
49
-	 */
50
-	protected $instances = [];
51
-
52
-	/**
53
-	 * @var array Structure: App => string[]
54
-	 */
55
-	protected $availableLanguages = [];
56
-
57
-	/**
58
-	 * @var array Structure: string => callable
59
-	 */
60
-	protected $pluralFunctions = [];
61
-
62
-	/** @var IConfig */
63
-	protected $config;
64
-
65
-	/** @var IRequest */
66
-	protected $request;
67
-
68
-	/** @var IUserSession */
69
-	protected $userSession;
70
-
71
-	/** @var string */
72
-	protected $serverRoot;
73
-
74
-	/**
75
-	 * @param IConfig $config
76
-	 * @param IRequest $request
77
-	 * @param IUserSession $userSession
78
-	 * @param string $serverRoot
79
-	 */
80
-	public function __construct(IConfig $config,
81
-								IRequest $request,
82
-								IUserSession $userSession,
83
-								$serverRoot) {
84
-		$this->config = $config;
85
-		$this->request = $request;
86
-		$this->userSession = $userSession;
87
-		$this->serverRoot = $serverRoot;
88
-	}
89
-
90
-	/**
91
-	 * Get a language instance
92
-	 *
93
-	 * @param string $app
94
-	 * @param string|null $lang
95
-	 * @return \OCP\IL10N
96
-	 */
97
-	public function get($app, $lang = null) {
98
-		$app = \OC_App::cleanAppId($app);
99
-		if ($lang !== null) {
100
-			$lang = str_replace(array('\0', '/', '\\', '..'), '', (string) $lang);
101
-		}
102
-		if ($lang === null || !$this->languageExists($app, $lang)) {
103
-			$lang = $this->findLanguage($app);
104
-		}
105
-
106
-		if (!isset($this->instances[$lang][$app])) {
107
-			$this->instances[$lang][$app] = new L10N(
108
-				$this, $app, $lang,
109
-				$this->getL10nFilesForApp($app, $lang)
110
-			);
111
-		}
112
-
113
-		return $this->instances[$lang][$app];
114
-	}
115
-
116
-	/**
117
-	 * Find the best language
118
-	 *
119
-	 * @param string|null $app App id or null for core
120
-	 * @return string language If nothing works it returns 'en'
121
-	 */
122
-	public function findLanguage($app = null) {
123
-		if ($this->requestLanguage !== '' && $this->languageExists($app, $this->requestLanguage)) {
124
-			return $this->requestLanguage;
125
-		}
126
-
127
-		/**
128
-		 * At this point ownCloud might not yet be installed and thus the lookup
129
-		 * in the preferences table might fail. For this reason we need to check
130
-		 * whether the instance has already been installed
131
-		 *
132
-		 * @link https://github.com/owncloud/core/issues/21955
133
-		 */
134
-		if($this->config->getSystemValue('installed', false)) {
135
-			$userId = !is_null($this->userSession->getUser()) ? $this->userSession->getUser()->getUID() :  null;
136
-			if(!is_null($userId)) {
137
-				$userLang = $this->config->getUserValue($userId, 'core', 'lang', null);
138
-			} else {
139
-				$userLang = null;
140
-			}
141
-		} else {
142
-			$userId = null;
143
-			$userLang = null;
144
-		}
145
-
146
-		if ($userLang) {
147
-			$this->requestLanguage = $userLang;
148
-			if ($this->languageExists($app, $userLang)) {
149
-				return $userLang;
150
-			}
151
-		}
152
-
153
-		try {
154
-			// Try to get the language from the Request
155
-			$lang = $this->getLanguageFromRequest($app);
156
-			if ($userId !== null && $app === null && !$userLang) {
157
-				$this->config->setUserValue($userId, 'core', 'lang', $lang);
158
-			}
159
-			return $lang;
160
-		} catch (LanguageNotFoundException $e) {
161
-			// Finding language from request failed fall back to default language
162
-			$defaultLanguage = $this->config->getSystemValue('default_language', false);
163
-			if ($defaultLanguage !== false && $this->languageExists($app, $defaultLanguage)) {
164
-				return $defaultLanguage;
165
-			}
166
-		}
167
-
168
-		// We could not find any language so fall back to english
169
-		return 'en';
170
-	}
171
-
172
-	/**
173
-	 * Find all available languages for an app
174
-	 *
175
-	 * @param string|null $app App id or null for core
176
-	 * @return array an array of available languages
177
-	 */
178
-	public function findAvailableLanguages($app = null) {
179
-		$key = $app;
180
-		if ($key === null) {
181
-			$key = 'null';
182
-		}
183
-
184
-		// also works with null as key
185
-		if (!empty($this->availableLanguages[$key])) {
186
-			return $this->availableLanguages[$key];
187
-		}
188
-
189
-		$available = ['en']; //english is always available
190
-		$dir = $this->findL10nDir($app);
191
-		if (is_dir($dir)) {
192
-			$files = scandir($dir);
193
-			if ($files !== false) {
194
-				foreach ($files as $file) {
195
-					if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
196
-						$available[] = substr($file, 0, -5);
197
-					}
198
-				}
199
-			}
200
-		}
201
-
202
-		// merge with translations from theme
203
-		$theme = $this->config->getSystemValue('theme');
204
-		if (!empty($theme)) {
205
-			$themeDir = $this->serverRoot . '/themes/' . $theme . substr($dir, strlen($this->serverRoot));
206
-
207
-			if (is_dir($themeDir)) {
208
-				$files = scandir($themeDir);
209
-				if ($files !== false) {
210
-					foreach ($files as $file) {
211
-						if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
212
-							$available[] = substr($file, 0, -5);
213
-						}
214
-					}
215
-				}
216
-			}
217
-		}
218
-
219
-		$this->availableLanguages[$key] = $available;
220
-		return $available;
221
-	}
222
-
223
-	/**
224
-	 * @param string|null $app App id or null for core
225
-	 * @param string $lang
226
-	 * @return bool
227
-	 */
228
-	public function languageExists($app, $lang) {
229
-		if ($lang === 'en') {//english is always available
230
-			return true;
231
-		}
232
-
233
-		$languages = $this->findAvailableLanguages($app);
234
-		return array_search($lang, $languages) !== false;
235
-	}
236
-
237
-	/**
238
-	 * @param string|null $app
239
-	 * @return string
240
-	 * @throws LanguageNotFoundException
241
-	 */
242
-	private function getLanguageFromRequest($app) {
243
-		$header = $this->request->getHeader('ACCEPT_LANGUAGE');
244
-		if ($header) {
245
-			$available = $this->findAvailableLanguages($app);
246
-
247
-			// E.g. make sure that 'de' is before 'de_DE'.
248
-			sort($available);
249
-
250
-			$preferences = preg_split('/,\s*/', strtolower($header));
251
-			foreach ($preferences as $preference) {
252
-				list($preferred_language) = explode(';', $preference);
253
-				$preferred_language = str_replace('-', '_', $preferred_language);
254
-
255
-				foreach ($available as $available_language) {
256
-					if ($preferred_language === strtolower($available_language)) {
257
-						return $available_language;
258
-					}
259
-				}
260
-
261
-				// Fallback from de_De to de
262
-				foreach ($available as $available_language) {
263
-					if (substr($preferred_language, 0, 2) === $available_language) {
264
-						return $available_language;
265
-					}
266
-				}
267
-			}
268
-		}
269
-
270
-		throw new LanguageNotFoundException();
271
-	}
272
-
273
-	/**
274
-	 * @param string|null $app App id or null for core
275
-	 * @return string
276
-	 */
277
-	public function setLanguageFromRequest($app = null) {
278
-
279
-		try {
280
-			$requestLanguage = $this->getLanguageFromRequest($app);
281
-		} catch (LanguageNotFoundException $e) {
282
-			$requestLanguage = 'en';
283
-		}
284
-
285
-		if ($app === null && !$this->requestLanguage) {
286
-			$this->requestLanguage = $requestLanguage;
287
-		}
288
-		return $requestLanguage;
289
-	}
290
-
291
-	/**
292
-	 * Checks if $sub is a subdirectory of $parent
293
-	 *
294
-	 * @param string $sub
295
-	 * @param string $parent
296
-	 * @return bool
297
-	 */
298
-	private function isSubDirectory($sub, $parent) {
299
-		// Check whether $sub contains no ".."
300
-		if(strpos($sub, '..') !== false) {
301
-			return false;
302
-		}
303
-
304
-		// Check whether $sub is a subdirectory of $parent
305
-		if (strpos($sub, $parent) === 0) {
306
-			return true;
307
-		}
308
-
309
-		return false;
310
-	}
311
-
312
-	/**
313
-	 * Get a list of language files that should be loaded
314
-	 *
315
-	 * @param string $app
316
-	 * @param string $lang
317
-	 * @return string[]
318
-	 */
319
-	// FIXME This method is only public, until OC_L10N does not need it anymore,
320
-	// FIXME This is also the reason, why it is not in the public interface
321
-	public function getL10nFilesForApp($app, $lang) {
322
-		$languageFiles = [];
323
-
324
-		$i18nDir = $this->findL10nDir($app);
325
-		$transFile = strip_tags($i18nDir) . strip_tags($lang) . '.json';
326
-
327
-		if (($this->isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
328
-				|| $this->isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
329
-				|| $this->isSubDirectory($transFile, $this->serverRoot . '/settings/l10n/')
330
-				|| $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
331
-			)
332
-			&& file_exists($transFile)) {
333
-			// load the translations file
334
-			$languageFiles[] = $transFile;
335
-		}
336
-
337
-		// merge with translations from theme
338
-		$theme = $this->config->getSystemValue('theme');
339
-		if (!empty($theme)) {
340
-			$transFile = $this->serverRoot . '/themes/' . $theme . substr($transFile, strlen($this->serverRoot));
341
-			if (file_exists($transFile)) {
342
-				$languageFiles[] = $transFile;
343
-			}
344
-		}
345
-
346
-		return $languageFiles;
347
-	}
348
-
349
-	/**
350
-	 * find the l10n directory
351
-	 *
352
-	 * @param string $app App id or empty string for core
353
-	 * @return string directory
354
-	 */
355
-	protected function findL10nDir($app = null) {
356
-		if (in_array($app, ['core', 'lib', 'settings'])) {
357
-			if (file_exists($this->serverRoot . '/' . $app . '/l10n/')) {
358
-				return $this->serverRoot . '/' . $app . '/l10n/';
359
-			}
360
-		} else if ($app && \OC_App::getAppPath($app) !== false) {
361
-			// Check if the app is in the app folder
362
-			return \OC_App::getAppPath($app) . '/l10n/';
363
-		}
364
-		return $this->serverRoot . '/core/l10n/';
365
-	}
366
-
367
-
368
-	/**
369
-	 * Creates a function from the plural string
370
-	 *
371
-	 * Parts of the code is copied from Habari:
372
-	 * https://github.com/habari/system/blob/master/classes/locale.php
373
-	 * @param string $string
374
-	 * @return string
375
-	 */
376
-	public function createPluralFunction($string) {
377
-		if (isset($this->pluralFunctions[$string])) {
378
-			return $this->pluralFunctions[$string];
379
-		}
380
-
381
-		if (preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
382
-			// sanitize
383
-			$nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
384
-			$plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );
385
-
386
-			$body = str_replace(
387
-				array( 'plural', 'n', '$n$plurals', ),
388
-				array( '$plural', '$n', '$nplurals', ),
389
-				'nplurals='. $nplurals . '; plural=' . $plural
390
-			);
391
-
392
-			// add parents
393
-			// important since PHP's ternary evaluates from left to right
394
-			$body .= ';';
395
-			$res = '';
396
-			$p = 0;
397
-			for($i = 0; $i < strlen($body); $i++) {
398
-				$ch = $body[$i];
399
-				switch ( $ch ) {
400
-					case '?':
401
-						$res .= ' ? (';
402
-						$p++;
403
-						break;
404
-					case ':':
405
-						$res .= ') : (';
406
-						break;
407
-					case ';':
408
-						$res .= str_repeat( ')', $p ) . ';';
409
-						$p = 0;
410
-						break;
411
-					default:
412
-						$res .= $ch;
413
-				}
414
-			}
415
-
416
-			$body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
417
-			$function = create_function('$n', $body);
418
-			$this->pluralFunctions[$string] = $function;
419
-			return $function;
420
-		} else {
421
-			// default: one plural form for all cases but n==1 (english)
422
-			$function = create_function(
423
-				'$n',
424
-				'$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);'
425
-			);
426
-			$this->pluralFunctions[$string] = $function;
427
-			return $function;
428
-		}
429
-	}
43
+    /** @var string */
44
+    protected $requestLanguage = '';
45
+
46
+    /**
47
+     * cached instances
48
+     * @var array Structure: Lang => App => \OCP\IL10N
49
+     */
50
+    protected $instances = [];
51
+
52
+    /**
53
+     * @var array Structure: App => string[]
54
+     */
55
+    protected $availableLanguages = [];
56
+
57
+    /**
58
+     * @var array Structure: string => callable
59
+     */
60
+    protected $pluralFunctions = [];
61
+
62
+    /** @var IConfig */
63
+    protected $config;
64
+
65
+    /** @var IRequest */
66
+    protected $request;
67
+
68
+    /** @var IUserSession */
69
+    protected $userSession;
70
+
71
+    /** @var string */
72
+    protected $serverRoot;
73
+
74
+    /**
75
+     * @param IConfig $config
76
+     * @param IRequest $request
77
+     * @param IUserSession $userSession
78
+     * @param string $serverRoot
79
+     */
80
+    public function __construct(IConfig $config,
81
+                                IRequest $request,
82
+                                IUserSession $userSession,
83
+                                $serverRoot) {
84
+        $this->config = $config;
85
+        $this->request = $request;
86
+        $this->userSession = $userSession;
87
+        $this->serverRoot = $serverRoot;
88
+    }
89
+
90
+    /**
91
+     * Get a language instance
92
+     *
93
+     * @param string $app
94
+     * @param string|null $lang
95
+     * @return \OCP\IL10N
96
+     */
97
+    public function get($app, $lang = null) {
98
+        $app = \OC_App::cleanAppId($app);
99
+        if ($lang !== null) {
100
+            $lang = str_replace(array('\0', '/', '\\', '..'), '', (string) $lang);
101
+        }
102
+        if ($lang === null || !$this->languageExists($app, $lang)) {
103
+            $lang = $this->findLanguage($app);
104
+        }
105
+
106
+        if (!isset($this->instances[$lang][$app])) {
107
+            $this->instances[$lang][$app] = new L10N(
108
+                $this, $app, $lang,
109
+                $this->getL10nFilesForApp($app, $lang)
110
+            );
111
+        }
112
+
113
+        return $this->instances[$lang][$app];
114
+    }
115
+
116
+    /**
117
+     * Find the best language
118
+     *
119
+     * @param string|null $app App id or null for core
120
+     * @return string language If nothing works it returns 'en'
121
+     */
122
+    public function findLanguage($app = null) {
123
+        if ($this->requestLanguage !== '' && $this->languageExists($app, $this->requestLanguage)) {
124
+            return $this->requestLanguage;
125
+        }
126
+
127
+        /**
128
+         * At this point ownCloud might not yet be installed and thus the lookup
129
+         * in the preferences table might fail. For this reason we need to check
130
+         * whether the instance has already been installed
131
+         *
132
+         * @link https://github.com/owncloud/core/issues/21955
133
+         */
134
+        if($this->config->getSystemValue('installed', false)) {
135
+            $userId = !is_null($this->userSession->getUser()) ? $this->userSession->getUser()->getUID() :  null;
136
+            if(!is_null($userId)) {
137
+                $userLang = $this->config->getUserValue($userId, 'core', 'lang', null);
138
+            } else {
139
+                $userLang = null;
140
+            }
141
+        } else {
142
+            $userId = null;
143
+            $userLang = null;
144
+        }
145
+
146
+        if ($userLang) {
147
+            $this->requestLanguage = $userLang;
148
+            if ($this->languageExists($app, $userLang)) {
149
+                return $userLang;
150
+            }
151
+        }
152
+
153
+        try {
154
+            // Try to get the language from the Request
155
+            $lang = $this->getLanguageFromRequest($app);
156
+            if ($userId !== null && $app === null && !$userLang) {
157
+                $this->config->setUserValue($userId, 'core', 'lang', $lang);
158
+            }
159
+            return $lang;
160
+        } catch (LanguageNotFoundException $e) {
161
+            // Finding language from request failed fall back to default language
162
+            $defaultLanguage = $this->config->getSystemValue('default_language', false);
163
+            if ($defaultLanguage !== false && $this->languageExists($app, $defaultLanguage)) {
164
+                return $defaultLanguage;
165
+            }
166
+        }
167
+
168
+        // We could not find any language so fall back to english
169
+        return 'en';
170
+    }
171
+
172
+    /**
173
+     * Find all available languages for an app
174
+     *
175
+     * @param string|null $app App id or null for core
176
+     * @return array an array of available languages
177
+     */
178
+    public function findAvailableLanguages($app = null) {
179
+        $key = $app;
180
+        if ($key === null) {
181
+            $key = 'null';
182
+        }
183
+
184
+        // also works with null as key
185
+        if (!empty($this->availableLanguages[$key])) {
186
+            return $this->availableLanguages[$key];
187
+        }
188
+
189
+        $available = ['en']; //english is always available
190
+        $dir = $this->findL10nDir($app);
191
+        if (is_dir($dir)) {
192
+            $files = scandir($dir);
193
+            if ($files !== false) {
194
+                foreach ($files as $file) {
195
+                    if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
196
+                        $available[] = substr($file, 0, -5);
197
+                    }
198
+                }
199
+            }
200
+        }
201
+
202
+        // merge with translations from theme
203
+        $theme = $this->config->getSystemValue('theme');
204
+        if (!empty($theme)) {
205
+            $themeDir = $this->serverRoot . '/themes/' . $theme . substr($dir, strlen($this->serverRoot));
206
+
207
+            if (is_dir($themeDir)) {
208
+                $files = scandir($themeDir);
209
+                if ($files !== false) {
210
+                    foreach ($files as $file) {
211
+                        if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
212
+                            $available[] = substr($file, 0, -5);
213
+                        }
214
+                    }
215
+                }
216
+            }
217
+        }
218
+
219
+        $this->availableLanguages[$key] = $available;
220
+        return $available;
221
+    }
222
+
223
+    /**
224
+     * @param string|null $app App id or null for core
225
+     * @param string $lang
226
+     * @return bool
227
+     */
228
+    public function languageExists($app, $lang) {
229
+        if ($lang === 'en') {//english is always available
230
+            return true;
231
+        }
232
+
233
+        $languages = $this->findAvailableLanguages($app);
234
+        return array_search($lang, $languages) !== false;
235
+    }
236
+
237
+    /**
238
+     * @param string|null $app
239
+     * @return string
240
+     * @throws LanguageNotFoundException
241
+     */
242
+    private function getLanguageFromRequest($app) {
243
+        $header = $this->request->getHeader('ACCEPT_LANGUAGE');
244
+        if ($header) {
245
+            $available = $this->findAvailableLanguages($app);
246
+
247
+            // E.g. make sure that 'de' is before 'de_DE'.
248
+            sort($available);
249
+
250
+            $preferences = preg_split('/,\s*/', strtolower($header));
251
+            foreach ($preferences as $preference) {
252
+                list($preferred_language) = explode(';', $preference);
253
+                $preferred_language = str_replace('-', '_', $preferred_language);
254
+
255
+                foreach ($available as $available_language) {
256
+                    if ($preferred_language === strtolower($available_language)) {
257
+                        return $available_language;
258
+                    }
259
+                }
260
+
261
+                // Fallback from de_De to de
262
+                foreach ($available as $available_language) {
263
+                    if (substr($preferred_language, 0, 2) === $available_language) {
264
+                        return $available_language;
265
+                    }
266
+                }
267
+            }
268
+        }
269
+
270
+        throw new LanguageNotFoundException();
271
+    }
272
+
273
+    /**
274
+     * @param string|null $app App id or null for core
275
+     * @return string
276
+     */
277
+    public function setLanguageFromRequest($app = null) {
278
+
279
+        try {
280
+            $requestLanguage = $this->getLanguageFromRequest($app);
281
+        } catch (LanguageNotFoundException $e) {
282
+            $requestLanguage = 'en';
283
+        }
284
+
285
+        if ($app === null && !$this->requestLanguage) {
286
+            $this->requestLanguage = $requestLanguage;
287
+        }
288
+        return $requestLanguage;
289
+    }
290
+
291
+    /**
292
+     * Checks if $sub is a subdirectory of $parent
293
+     *
294
+     * @param string $sub
295
+     * @param string $parent
296
+     * @return bool
297
+     */
298
+    private function isSubDirectory($sub, $parent) {
299
+        // Check whether $sub contains no ".."
300
+        if(strpos($sub, '..') !== false) {
301
+            return false;
302
+        }
303
+
304
+        // Check whether $sub is a subdirectory of $parent
305
+        if (strpos($sub, $parent) === 0) {
306
+            return true;
307
+        }
308
+
309
+        return false;
310
+    }
311
+
312
+    /**
313
+     * Get a list of language files that should be loaded
314
+     *
315
+     * @param string $app
316
+     * @param string $lang
317
+     * @return string[]
318
+     */
319
+    // FIXME This method is only public, until OC_L10N does not need it anymore,
320
+    // FIXME This is also the reason, why it is not in the public interface
321
+    public function getL10nFilesForApp($app, $lang) {
322
+        $languageFiles = [];
323
+
324
+        $i18nDir = $this->findL10nDir($app);
325
+        $transFile = strip_tags($i18nDir) . strip_tags($lang) . '.json';
326
+
327
+        if (($this->isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
328
+                || $this->isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
329
+                || $this->isSubDirectory($transFile, $this->serverRoot . '/settings/l10n/')
330
+                || $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
331
+            )
332
+            && file_exists($transFile)) {
333
+            // load the translations file
334
+            $languageFiles[] = $transFile;
335
+        }
336
+
337
+        // merge with translations from theme
338
+        $theme = $this->config->getSystemValue('theme');
339
+        if (!empty($theme)) {
340
+            $transFile = $this->serverRoot . '/themes/' . $theme . substr($transFile, strlen($this->serverRoot));
341
+            if (file_exists($transFile)) {
342
+                $languageFiles[] = $transFile;
343
+            }
344
+        }
345
+
346
+        return $languageFiles;
347
+    }
348
+
349
+    /**
350
+     * find the l10n directory
351
+     *
352
+     * @param string $app App id or empty string for core
353
+     * @return string directory
354
+     */
355
+    protected function findL10nDir($app = null) {
356
+        if (in_array($app, ['core', 'lib', 'settings'])) {
357
+            if (file_exists($this->serverRoot . '/' . $app . '/l10n/')) {
358
+                return $this->serverRoot . '/' . $app . '/l10n/';
359
+            }
360
+        } else if ($app && \OC_App::getAppPath($app) !== false) {
361
+            // Check if the app is in the app folder
362
+            return \OC_App::getAppPath($app) . '/l10n/';
363
+        }
364
+        return $this->serverRoot . '/core/l10n/';
365
+    }
366
+
367
+
368
+    /**
369
+     * Creates a function from the plural string
370
+     *
371
+     * Parts of the code is copied from Habari:
372
+     * https://github.com/habari/system/blob/master/classes/locale.php
373
+     * @param string $string
374
+     * @return string
375
+     */
376
+    public function createPluralFunction($string) {
377
+        if (isset($this->pluralFunctions[$string])) {
378
+            return $this->pluralFunctions[$string];
379
+        }
380
+
381
+        if (preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
382
+            // sanitize
383
+            $nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
384
+            $plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );
385
+
386
+            $body = str_replace(
387
+                array( 'plural', 'n', '$n$plurals', ),
388
+                array( '$plural', '$n', '$nplurals', ),
389
+                'nplurals='. $nplurals . '; plural=' . $plural
390
+            );
391
+
392
+            // add parents
393
+            // important since PHP's ternary evaluates from left to right
394
+            $body .= ';';
395
+            $res = '';
396
+            $p = 0;
397
+            for($i = 0; $i < strlen($body); $i++) {
398
+                $ch = $body[$i];
399
+                switch ( $ch ) {
400
+                    case '?':
401
+                        $res .= ' ? (';
402
+                        $p++;
403
+                        break;
404
+                    case ':':
405
+                        $res .= ') : (';
406
+                        break;
407
+                    case ';':
408
+                        $res .= str_repeat( ')', $p ) . ';';
409
+                        $p = 0;
410
+                        break;
411
+                    default:
412
+                        $res .= $ch;
413
+                }
414
+            }
415
+
416
+            $body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
417
+            $function = create_function('$n', $body);
418
+            $this->pluralFunctions[$string] = $function;
419
+            return $function;
420
+        } else {
421
+            // default: one plural form for all cases but n==1 (english)
422
+            $function = create_function(
423
+                '$n',
424
+                '$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);'
425
+            );
426
+            $this->pluralFunctions[$string] = $function;
427
+            return $function;
428
+        }
429
+    }
430 430
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -131,9 +131,9 @@  discard block
 block discarded – undo
131 131
 		 *
132 132
 		 * @link https://github.com/owncloud/core/issues/21955
133 133
 		 */
134
-		if($this->config->getSystemValue('installed', false)) {
135
-			$userId = !is_null($this->userSession->getUser()) ? $this->userSession->getUser()->getUID() :  null;
136
-			if(!is_null($userId)) {
134
+		if ($this->config->getSystemValue('installed', false)) {
135
+			$userId = !is_null($this->userSession->getUser()) ? $this->userSession->getUser()->getUID() : null;
136
+			if (!is_null($userId)) {
137 137
 				$userLang = $this->config->getUserValue($userId, 'core', 'lang', null);
138 138
 			} else {
139 139
 				$userLang = null;
@@ -202,7 +202,7 @@  discard block
 block discarded – undo
202 202
 		// merge with translations from theme
203 203
 		$theme = $this->config->getSystemValue('theme');
204 204
 		if (!empty($theme)) {
205
-			$themeDir = $this->serverRoot . '/themes/' . $theme . substr($dir, strlen($this->serverRoot));
205
+			$themeDir = $this->serverRoot.'/themes/'.$theme.substr($dir, strlen($this->serverRoot));
206 206
 
207 207
 			if (is_dir($themeDir)) {
208 208
 				$files = scandir($themeDir);
@@ -297,7 +297,7 @@  discard block
 block discarded – undo
297 297
 	 */
298 298
 	private function isSubDirectory($sub, $parent) {
299 299
 		// Check whether $sub contains no ".."
300
-		if(strpos($sub, '..') !== false) {
300
+		if (strpos($sub, '..') !== false) {
301 301
 			return false;
302 302
 		}
303 303
 
@@ -322,12 +322,12 @@  discard block
 block discarded – undo
322 322
 		$languageFiles = [];
323 323
 
324 324
 		$i18nDir = $this->findL10nDir($app);
325
-		$transFile = strip_tags($i18nDir) . strip_tags($lang) . '.json';
325
+		$transFile = strip_tags($i18nDir).strip_tags($lang).'.json';
326 326
 
327
-		if (($this->isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
328
-				|| $this->isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
329
-				|| $this->isSubDirectory($transFile, $this->serverRoot . '/settings/l10n/')
330
-				|| $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
327
+		if (($this->isSubDirectory($transFile, $this->serverRoot.'/core/l10n/')
328
+				|| $this->isSubDirectory($transFile, $this->serverRoot.'/lib/l10n/')
329
+				|| $this->isSubDirectory($transFile, $this->serverRoot.'/settings/l10n/')
330
+				|| $this->isSubDirectory($transFile, \OC_App::getAppPath($app).'/l10n/')
331 331
 			)
332 332
 			&& file_exists($transFile)) {
333 333
 			// load the translations file
@@ -337,7 +337,7 @@  discard block
 block discarded – undo
337 337
 		// merge with translations from theme
338 338
 		$theme = $this->config->getSystemValue('theme');
339 339
 		if (!empty($theme)) {
340
-			$transFile = $this->serverRoot . '/themes/' . $theme . substr($transFile, strlen($this->serverRoot));
340
+			$transFile = $this->serverRoot.'/themes/'.$theme.substr($transFile, strlen($this->serverRoot));
341 341
 			if (file_exists($transFile)) {
342 342
 				$languageFiles[] = $transFile;
343 343
 			}
@@ -354,14 +354,14 @@  discard block
 block discarded – undo
354 354
 	 */
355 355
 	protected function findL10nDir($app = null) {
356 356
 		if (in_array($app, ['core', 'lib', 'settings'])) {
357
-			if (file_exists($this->serverRoot . '/' . $app . '/l10n/')) {
358
-				return $this->serverRoot . '/' . $app . '/l10n/';
357
+			if (file_exists($this->serverRoot.'/'.$app.'/l10n/')) {
358
+				return $this->serverRoot.'/'.$app.'/l10n/';
359 359
 			}
360 360
 		} else if ($app && \OC_App::getAppPath($app) !== false) {
361 361
 			// Check if the app is in the app folder
362
-			return \OC_App::getAppPath($app) . '/l10n/';
362
+			return \OC_App::getAppPath($app).'/l10n/';
363 363
 		}
364
-		return $this->serverRoot . '/core/l10n/';
364
+		return $this->serverRoot.'/core/l10n/';
365 365
 	}
366 366
 
367 367
 
@@ -378,15 +378,15 @@  discard block
 block discarded – undo
378 378
 			return $this->pluralFunctions[$string];
379 379
 		}
380 380
 
381
-		if (preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
381
+		if (preg_match('/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
382 382
 			// sanitize
383
-			$nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
384
-			$plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );
383
+			$nplurals = preg_replace('/[^0-9]/', '', $matches[1]);
384
+			$plural = preg_replace('#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2]);
385 385
 
386 386
 			$body = str_replace(
387
-				array( 'plural', 'n', '$n$plurals', ),
388
-				array( '$plural', '$n', '$nplurals', ),
389
-				'nplurals='. $nplurals . '; plural=' . $plural
387
+				array('plural', 'n', '$n$plurals',),
388
+				array('$plural', '$n', '$nplurals',),
389
+				'nplurals='.$nplurals.'; plural='.$plural
390 390
 			);
391 391
 
392 392
 			// add parents
@@ -394,9 +394,9 @@  discard block
 block discarded – undo
394 394
 			$body .= ';';
395 395
 			$res = '';
396 396
 			$p = 0;
397
-			for($i = 0; $i < strlen($body); $i++) {
397
+			for ($i = 0; $i < strlen($body); $i++) {
398 398
 				$ch = $body[$i];
399
-				switch ( $ch ) {
399
+				switch ($ch) {
400 400
 					case '?':
401 401
 						$res .= ' ? (';
402 402
 						$p++;
@@ -405,7 +405,7 @@  discard block
 block discarded – undo
405 405
 						$res .= ') : (';
406 406
 						break;
407 407
 					case ';':
408
-						$res .= str_repeat( ')', $p ) . ';';
408
+						$res .= str_repeat(')', $p).';';
409 409
 						$p = 0;
410 410
 						break;
411 411
 					default:
@@ -413,7 +413,7 @@  discard block
 block discarded – undo
413 413
 				}
414 414
 			}
415 415
 
416
-			$body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
416
+			$body = $res.'return ($plural>=$nplurals?$nplurals-1:$plural);';
417 417
 			$function = create_function('$n', $body);
418 418
 			$this->pluralFunctions[$string] = $function;
419 419
 			return $function;
Please login to merge, or discard this patch.
lib/private/Installer.php 4 patches
Unused Use Statements   -1 removed lines patch added patch discarded remove patch
@@ -45,7 +45,6 @@
 block discarded – undo
45 45
 use OC\App\CodeChecker\CodeChecker;
46 46
 use OC\App\CodeChecker\EmptyCheck;
47 47
 use OC\App\CodeChecker\PrivateCheck;
48
-use OC\Archive\Archive;
49 48
 use OC\Archive\TAR;
50 49
 use OC_App;
51 50
 use OC_DB;
Please login to merge, or discard this patch.
Indentation   +489 added lines, -489 removed lines patch added patch discarded remove patch
@@ -60,493 +60,493 @@
 block discarded – undo
60 60
  * This class provides the functionality needed to install, update and remove apps
61 61
  */
62 62
 class Installer {
63
-	/** @var AppFetcher */
64
-	private $appFetcher;
65
-	/** @var IClientService */
66
-	private $clientService;
67
-	/** @var ITempManager */
68
-	private $tempManager;
69
-	/** @var ILogger */
70
-	private $logger;
71
-
72
-	/**
73
-	 * @param AppFetcher $appFetcher
74
-	 * @param IClientService $clientService
75
-	 * @param ITempManager $tempManager
76
-	 * @param ILogger $logger
77
-	 */
78
-	public function __construct(AppFetcher $appFetcher,
79
-								IClientService $clientService,
80
-								ITempManager $tempManager,
81
-								ILogger $logger) {
82
-		$this->appFetcher = $appFetcher;
83
-		$this->clientService = $clientService;
84
-		$this->tempManager = $tempManager;
85
-		$this->logger = $logger;
86
-	}
87
-
88
-	/**
89
-	 * Installs an app that is located in one of the app folders already
90
-	 *
91
-	 * @param string $appId App to install
92
-	 * @throws \Exception
93
-	 * @return integer
94
-	 */
95
-	public function installApp($appId) {
96
-		$app = \OC_App::findAppInDirectories($appId);
97
-		if($app === false) {
98
-			throw new \Exception('App not found in any app directory');
99
-		}
100
-
101
-		$basedir = $app['path'].'/'.$appId;
102
-		$info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true);
103
-
104
-		//install the database
105
-		if(is_file($basedir.'/appinfo/database.xml')) {
106
-			if (\OC::$server->getAppConfig()->getValue($info['id'], 'installed_version') === null) {
107
-				OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml');
108
-			} else {
109
-				OC_DB::updateDbFromStructure($basedir.'/appinfo/database.xml');
110
-			}
111
-		}
112
-
113
-		\OC_App::setupBackgroundJobs($info['background-jobs']);
114
-
115
-		//run appinfo/install.php
116
-		if((!isset($data['noinstall']) or $data['noinstall']==false)) {
117
-			self::includeAppScript($basedir . '/appinfo/install.php');
118
-		}
119
-
120
-		$appData = OC_App::getAppInfo($appId);
121
-		OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']);
122
-
123
-		//set the installed version
124
-		\OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'], false));
125
-		\OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no');
126
-
127
-		//set remote/public handlers
128
-		foreach($info['remote'] as $name=>$path) {
129
-			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path);
130
-		}
131
-		foreach($info['public'] as $name=>$path) {
132
-			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path);
133
-		}
134
-
135
-		OC_App::setAppTypes($info['id']);
136
-
137
-		return $info['id'];
138
-	}
139
-
140
-	/**
141
-	 * @brief checks whether or not an app is installed
142
-	 * @param string $app app
143
-	 * @returns bool
144
-	 *
145
-	 * Checks whether or not an app is installed, i.e. registered in apps table.
146
-	 */
147
-	public static function isInstalled( $app ) {
148
-		return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null);
149
-	}
150
-
151
-	/**
152
-	 * Updates the specified app from the appstore
153
-	 *
154
-	 * @param string $appId
155
-	 * @return bool
156
-	 */
157
-	public function updateAppstoreApp($appId) {
158
-		if(self::isUpdateAvailable($appId, $this->appFetcher)) {
159
-			try {
160
-				$this->downloadApp($appId);
161
-			} catch (\Exception $e) {
162
-				$this->logger->error($e->getMessage(), ['app' => 'core']);
163
-				return false;
164
-			}
165
-			return OC_App::updateApp($appId);
166
-		}
167
-
168
-		return false;
169
-	}
170
-
171
-	/**
172
-	 * Downloads an app and puts it into the app directory
173
-	 *
174
-	 * @param string $appId
175
-	 *
176
-	 * @throws \Exception If the installation was not successful
177
-	 */
178
-	public function downloadApp($appId) {
179
-		$appId = strtolower($appId);
180
-
181
-		$apps = $this->appFetcher->get();
182
-		foreach($apps as $app) {
183
-			if($app['id'] === $appId) {
184
-				// Load the certificate
185
-				$certificate = new X509();
186
-				$certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
187
-				$loadedCertificate = $certificate->loadX509($app['certificate']);
188
-
189
-				// Verify if the certificate has been revoked
190
-				$crl = new X509();
191
-				$crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
192
-				$crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl'));
193
-				if($crl->validateSignature() !== true) {
194
-					throw new \Exception('Could not validate CRL signature');
195
-				}
196
-				$csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString();
197
-				$revoked = $crl->getRevoked($csn);
198
-				if ($revoked !== false) {
199
-					throw new \Exception(
200
-						sprintf(
201
-							'Certificate "%s" has been revoked',
202
-							$csn
203
-						)
204
-					);
205
-				}
206
-
207
-				// Verify if the certificate has been issued by the Nextcloud Code Authority CA
208
-				if($certificate->validateSignature() !== true) {
209
-					throw new \Exception(
210
-						sprintf(
211
-							'App with id %s has a certificate not issued by a trusted Code Signing Authority',
212
-							$appId
213
-						)
214
-					);
215
-				}
216
-
217
-				// Verify if the certificate is issued for the requested app id
218
-				$certInfo = openssl_x509_parse($app['certificate']);
219
-				if(!isset($certInfo['subject']['CN'])) {
220
-					throw new \Exception(
221
-						sprintf(
222
-							'App with id %s has a cert with no CN',
223
-							$appId
224
-						)
225
-					);
226
-				}
227
-				if($certInfo['subject']['CN'] !== $appId) {
228
-					throw new \Exception(
229
-						sprintf(
230
-							'App with id %s has a cert issued to %s',
231
-							$appId,
232
-							$certInfo['subject']['CN']
233
-						)
234
-					);
235
-				}
236
-
237
-				// Download the release
238
-				$tempFile = $this->tempManager->getTemporaryFile('.tar.gz');
239
-				$client = $this->clientService->newClient();
240
-				$client->get($app['releases'][0]['download'], ['save_to' => $tempFile]);
241
-
242
-				// Check if the signature actually matches the downloaded content
243
-				$certificate = openssl_get_publickey($app['certificate']);
244
-				$verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
245
-				openssl_free_key($certificate);
246
-
247
-				if($verified === true) {
248
-					// Seems to match, let's proceed
249
-					$extractDir = $this->tempManager->getTemporaryFolder();
250
-					$archive = new TAR($tempFile);
251
-
252
-					if($archive) {
253
-						$archive->extract($extractDir);
254
-						$allFiles = scandir($extractDir);
255
-						$folders = array_diff($allFiles, ['.', '..']);
256
-						$folders = array_values($folders);
257
-
258
-						if(count($folders) > 1) {
259
-							throw new \Exception(
260
-								sprintf(
261
-									'Extracted app %s has more than 1 folder',
262
-									$appId
263
-								)
264
-							);
265
-						}
266
-
267
-						// Check if appinfo/info.xml has the same app ID as well
268
-						$loadEntities = libxml_disable_entity_loader(false);
269
-						$xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
270
-						libxml_disable_entity_loader($loadEntities);
271
-						if((string)$xml->id !== $appId) {
272
-							throw new \Exception(
273
-								sprintf(
274
-									'App for id %s has a wrong app ID in info.xml: %s',
275
-									$appId,
276
-									(string)$xml->id
277
-								)
278
-							);
279
-						}
280
-
281
-						// Check if the version is lower than before
282
-						$currentVersion = OC_App::getAppVersion($appId);
283
-						$newVersion = (string)$xml->version;
284
-						if(version_compare($currentVersion, $newVersion) === 1) {
285
-							throw new \Exception(
286
-								sprintf(
287
-									'App for id %s has version %s and tried to update to lower version %s',
288
-									$appId,
289
-									$currentVersion,
290
-									$newVersion
291
-								)
292
-							);
293
-						}
294
-
295
-						$baseDir = OC_App::getInstallPath() . '/' . $appId;
296
-						// Remove old app with the ID if existent
297
-						OC_Helper::rmdirr($baseDir);
298
-						// Move to app folder
299
-						if(@mkdir($baseDir)) {
300
-							$extractDir .= '/' . $folders[0];
301
-							OC_Helper::copyr($extractDir, $baseDir);
302
-						}
303
-						OC_Helper::copyr($extractDir, $baseDir);
304
-						OC_Helper::rmdirr($extractDir);
305
-						return;
306
-					} else {
307
-						throw new \Exception(
308
-							sprintf(
309
-								'Could not extract app with ID %s to %s',
310
-								$appId,
311
-								$extractDir
312
-							)
313
-						);
314
-					}
315
-				} else {
316
-					// Signature does not match
317
-					throw new \Exception(
318
-						sprintf(
319
-							'App with id %s has invalid signature',
320
-							$appId
321
-						)
322
-					);
323
-				}
324
-			}
325
-		}
326
-
327
-		throw new \Exception(
328
-			sprintf(
329
-				'Could not download app %s',
330
-				$appId
331
-			)
332
-		);
333
-	}
334
-
335
-	/**
336
-	 * Check if an update for the app is available
337
-	 *
338
-	 * @param string $appId
339
-	 * @param AppFetcher $appFetcher
340
-	 * @return string|false false or the version number of the update
341
-	 */
342
-	public static function isUpdateAvailable($appId,
343
-									  AppFetcher $appFetcher) {
344
-		static $isInstanceReadyForUpdates = null;
345
-
346
-		if ($isInstanceReadyForUpdates === null) {
347
-			$installPath = OC_App::getInstallPath();
348
-			if ($installPath === false || $installPath === null) {
349
-				$isInstanceReadyForUpdates = false;
350
-			} else {
351
-				$isInstanceReadyForUpdates = true;
352
-			}
353
-		}
354
-
355
-		if ($isInstanceReadyForUpdates === false) {
356
-			return false;
357
-		}
358
-
359
-		$apps = $appFetcher->get();
360
-		foreach($apps as $app) {
361
-			if($app['id'] === $appId) {
362
-				$currentVersion = OC_App::getAppVersion($appId);
363
-				$newestVersion = $app['releases'][0]['version'];
364
-				if (version_compare($newestVersion, $currentVersion, '>')) {
365
-					return $newestVersion;
366
-				} else {
367
-					return false;
368
-				}
369
-			}
370
-		}
371
-
372
-		return false;
373
-	}
374
-
375
-	/**
376
-	 * Check if app is already downloaded
377
-	 * @param string $name name of the application to remove
378
-	 * @return boolean
379
-	 *
380
-	 * The function will check if the app is already downloaded in the apps repository
381
-	 */
382
-	public function isDownloaded($name) {
383
-		foreach(\OC::$APPSROOTS as $dir) {
384
-			$dirToTest  = $dir['path'];
385
-			$dirToTest .= '/';
386
-			$dirToTest .= $name;
387
-			$dirToTest .= '/';
388
-
389
-			if (is_dir($dirToTest)) {
390
-				return true;
391
-			}
392
-		}
393
-
394
-		return false;
395
-	}
396
-
397
-	/**
398
-	 * Removes an app
399
-	 * @param string $appId ID of the application to remove
400
-	 * @return boolean
401
-	 *
402
-	 *
403
-	 * This function works as follows
404
-	 *   -# call uninstall repair steps
405
-	 *   -# removing the files
406
-	 *
407
-	 * The function will not delete preferences, tables and the configuration,
408
-	 * this has to be done by the function oc_app_uninstall().
409
-	 */
410
-	public function removeApp($appId) {
411
-		if($this->isDownloaded( $appId )) {
412
-			$appDir = OC_App::getInstallPath() . '/' . $appId;
413
-			OC_Helper::rmdirr($appDir);
414
-			return true;
415
-		}else{
416
-			\OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR);
417
-
418
-			return false;
419
-		}
420
-
421
-	}
422
-
423
-	/**
424
-	 * Installs shipped apps
425
-	 *
426
-	 * This function installs all apps found in the 'apps' directory that should be enabled by default;
427
-	 * @param bool $softErrors When updating we ignore errors and simply log them, better to have a
428
-	 *                         working ownCloud at the end instead of an aborted update.
429
-	 * @return array Array of error messages (appid => Exception)
430
-	 */
431
-	public static function installShippedApps($softErrors = false) {
432
-		$errors = [];
433
-		foreach(\OC::$APPSROOTS as $app_dir) {
434
-			if($dir = opendir( $app_dir['path'] )) {
435
-				while( false !== ( $filename = readdir( $dir ))) {
436
-					if( substr( $filename, 0, 1 ) != '.' and is_dir($app_dir['path']."/$filename") ) {
437
-						if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) {
438
-							if(!Installer::isInstalled($filename)) {
439
-								$info=OC_App::getAppInfo($filename);
440
-								$enabled = isset($info['default_enable']);
441
-								if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps()))
442
-									  && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') {
443
-									if ($softErrors) {
444
-										try {
445
-											Installer::installShippedApp($filename);
446
-										} catch (HintException $e) {
447
-											if ($e->getPrevious() instanceof TableExistsException) {
448
-												$errors[$filename] = $e;
449
-												continue;
450
-											}
451
-											throw $e;
452
-										}
453
-									} else {
454
-										Installer::installShippedApp($filename);
455
-									}
456
-									\OC::$server->getConfig()->setAppValue($filename, 'enabled', 'yes');
457
-								}
458
-							}
459
-						}
460
-					}
461
-				}
462
-				closedir( $dir );
463
-			}
464
-		}
465
-
466
-		return $errors;
467
-	}
468
-
469
-	/**
470
-	 * install an app already placed in the app folder
471
-	 * @param string $app id of the app to install
472
-	 * @return integer
473
-	 */
474
-	public static function installShippedApp($app) {
475
-		//install the database
476
-		$appPath = OC_App::getAppPath($app);
477
-		if(is_file("$appPath/appinfo/database.xml")) {
478
-			try {
479
-				OC_DB::createDbFromStructure("$appPath/appinfo/database.xml");
480
-			} catch (TableExistsException $e) {
481
-				throw new HintException(
482
-					'Failed to enable app ' . $app,
483
-					'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer">support channels</a>.',
484
-					0, $e
485
-				);
486
-			}
487
-		}
488
-
489
-		//run appinfo/install.php
490
-		\OC_App::registerAutoloading($app, $appPath);
491
-		self::includeAppScript("$appPath/appinfo/install.php");
492
-
493
-		$info = OC_App::getAppInfo($app);
494
-		if (is_null($info)) {
495
-			return false;
496
-		}
497
-		\OC_App::setupBackgroundJobs($info['background-jobs']);
498
-
499
-		OC_App::executeRepairSteps($app, $info['repair-steps']['install']);
500
-
501
-		$config = \OC::$server->getConfig();
502
-
503
-		$config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app));
504
-		if (array_key_exists('ocsid', $info)) {
505
-			$config->setAppValue($app, 'ocsid', $info['ocsid']);
506
-		}
507
-
508
-		//set remote/public handlers
509
-		foreach($info['remote'] as $name=>$path) {
510
-			$config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
511
-		}
512
-		foreach($info['public'] as $name=>$path) {
513
-			$config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
514
-		}
515
-
516
-		OC_App::setAppTypes($info['id']);
517
-
518
-		if(isset($info['settings']) && is_array($info['settings'])) {
519
-			// requires that autoloading was registered for the app,
520
-			// as happens before running the install.php some lines above
521
-			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
522
-		}
523
-
524
-		return $info['id'];
525
-	}
526
-
527
-	/**
528
-	 * check the code of an app with some static code checks
529
-	 * @param string $folder the folder of the app to check
530
-	 * @return boolean true for app is o.k. and false for app is not o.k.
531
-	 */
532
-	public static function checkCode($folder) {
533
-		// is the code checker enabled?
534
-		if(!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) {
535
-			return true;
536
-		}
537
-
538
-		$codeChecker = new CodeChecker(new PrivateCheck(new EmptyCheck()));
539
-		$errors = $codeChecker->analyseFolder(basename($folder), $folder);
540
-
541
-		return empty($errors);
542
-	}
543
-
544
-	/**
545
-	 * @param string $script
546
-	 */
547
-	private static function includeAppScript($script) {
548
-		if ( file_exists($script) ){
549
-			include $script;
550
-		}
551
-	}
63
+    /** @var AppFetcher */
64
+    private $appFetcher;
65
+    /** @var IClientService */
66
+    private $clientService;
67
+    /** @var ITempManager */
68
+    private $tempManager;
69
+    /** @var ILogger */
70
+    private $logger;
71
+
72
+    /**
73
+     * @param AppFetcher $appFetcher
74
+     * @param IClientService $clientService
75
+     * @param ITempManager $tempManager
76
+     * @param ILogger $logger
77
+     */
78
+    public function __construct(AppFetcher $appFetcher,
79
+                                IClientService $clientService,
80
+                                ITempManager $tempManager,
81
+                                ILogger $logger) {
82
+        $this->appFetcher = $appFetcher;
83
+        $this->clientService = $clientService;
84
+        $this->tempManager = $tempManager;
85
+        $this->logger = $logger;
86
+    }
87
+
88
+    /**
89
+     * Installs an app that is located in one of the app folders already
90
+     *
91
+     * @param string $appId App to install
92
+     * @throws \Exception
93
+     * @return integer
94
+     */
95
+    public function installApp($appId) {
96
+        $app = \OC_App::findAppInDirectories($appId);
97
+        if($app === false) {
98
+            throw new \Exception('App not found in any app directory');
99
+        }
100
+
101
+        $basedir = $app['path'].'/'.$appId;
102
+        $info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true);
103
+
104
+        //install the database
105
+        if(is_file($basedir.'/appinfo/database.xml')) {
106
+            if (\OC::$server->getAppConfig()->getValue($info['id'], 'installed_version') === null) {
107
+                OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml');
108
+            } else {
109
+                OC_DB::updateDbFromStructure($basedir.'/appinfo/database.xml');
110
+            }
111
+        }
112
+
113
+        \OC_App::setupBackgroundJobs($info['background-jobs']);
114
+
115
+        //run appinfo/install.php
116
+        if((!isset($data['noinstall']) or $data['noinstall']==false)) {
117
+            self::includeAppScript($basedir . '/appinfo/install.php');
118
+        }
119
+
120
+        $appData = OC_App::getAppInfo($appId);
121
+        OC_App::executeRepairSteps($appId, $appData['repair-steps']['install']);
122
+
123
+        //set the installed version
124
+        \OC::$server->getConfig()->setAppValue($info['id'], 'installed_version', OC_App::getAppVersion($info['id'], false));
125
+        \OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no');
126
+
127
+        //set remote/public handlers
128
+        foreach($info['remote'] as $name=>$path) {
129
+            \OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path);
130
+        }
131
+        foreach($info['public'] as $name=>$path) {
132
+            \OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path);
133
+        }
134
+
135
+        OC_App::setAppTypes($info['id']);
136
+
137
+        return $info['id'];
138
+    }
139
+
140
+    /**
141
+     * @brief checks whether or not an app is installed
142
+     * @param string $app app
143
+     * @returns bool
144
+     *
145
+     * Checks whether or not an app is installed, i.e. registered in apps table.
146
+     */
147
+    public static function isInstalled( $app ) {
148
+        return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null);
149
+    }
150
+
151
+    /**
152
+     * Updates the specified app from the appstore
153
+     *
154
+     * @param string $appId
155
+     * @return bool
156
+     */
157
+    public function updateAppstoreApp($appId) {
158
+        if(self::isUpdateAvailable($appId, $this->appFetcher)) {
159
+            try {
160
+                $this->downloadApp($appId);
161
+            } catch (\Exception $e) {
162
+                $this->logger->error($e->getMessage(), ['app' => 'core']);
163
+                return false;
164
+            }
165
+            return OC_App::updateApp($appId);
166
+        }
167
+
168
+        return false;
169
+    }
170
+
171
+    /**
172
+     * Downloads an app and puts it into the app directory
173
+     *
174
+     * @param string $appId
175
+     *
176
+     * @throws \Exception If the installation was not successful
177
+     */
178
+    public function downloadApp($appId) {
179
+        $appId = strtolower($appId);
180
+
181
+        $apps = $this->appFetcher->get();
182
+        foreach($apps as $app) {
183
+            if($app['id'] === $appId) {
184
+                // Load the certificate
185
+                $certificate = new X509();
186
+                $certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
187
+                $loadedCertificate = $certificate->loadX509($app['certificate']);
188
+
189
+                // Verify if the certificate has been revoked
190
+                $crl = new X509();
191
+                $crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
192
+                $crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl'));
193
+                if($crl->validateSignature() !== true) {
194
+                    throw new \Exception('Could not validate CRL signature');
195
+                }
196
+                $csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString();
197
+                $revoked = $crl->getRevoked($csn);
198
+                if ($revoked !== false) {
199
+                    throw new \Exception(
200
+                        sprintf(
201
+                            'Certificate "%s" has been revoked',
202
+                            $csn
203
+                        )
204
+                    );
205
+                }
206
+
207
+                // Verify if the certificate has been issued by the Nextcloud Code Authority CA
208
+                if($certificate->validateSignature() !== true) {
209
+                    throw new \Exception(
210
+                        sprintf(
211
+                            'App with id %s has a certificate not issued by a trusted Code Signing Authority',
212
+                            $appId
213
+                        )
214
+                    );
215
+                }
216
+
217
+                // Verify if the certificate is issued for the requested app id
218
+                $certInfo = openssl_x509_parse($app['certificate']);
219
+                if(!isset($certInfo['subject']['CN'])) {
220
+                    throw new \Exception(
221
+                        sprintf(
222
+                            'App with id %s has a cert with no CN',
223
+                            $appId
224
+                        )
225
+                    );
226
+                }
227
+                if($certInfo['subject']['CN'] !== $appId) {
228
+                    throw new \Exception(
229
+                        sprintf(
230
+                            'App with id %s has a cert issued to %s',
231
+                            $appId,
232
+                            $certInfo['subject']['CN']
233
+                        )
234
+                    );
235
+                }
236
+
237
+                // Download the release
238
+                $tempFile = $this->tempManager->getTemporaryFile('.tar.gz');
239
+                $client = $this->clientService->newClient();
240
+                $client->get($app['releases'][0]['download'], ['save_to' => $tempFile]);
241
+
242
+                // Check if the signature actually matches the downloaded content
243
+                $certificate = openssl_get_publickey($app['certificate']);
244
+                $verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
245
+                openssl_free_key($certificate);
246
+
247
+                if($verified === true) {
248
+                    // Seems to match, let's proceed
249
+                    $extractDir = $this->tempManager->getTemporaryFolder();
250
+                    $archive = new TAR($tempFile);
251
+
252
+                    if($archive) {
253
+                        $archive->extract($extractDir);
254
+                        $allFiles = scandir($extractDir);
255
+                        $folders = array_diff($allFiles, ['.', '..']);
256
+                        $folders = array_values($folders);
257
+
258
+                        if(count($folders) > 1) {
259
+                            throw new \Exception(
260
+                                sprintf(
261
+                                    'Extracted app %s has more than 1 folder',
262
+                                    $appId
263
+                                )
264
+                            );
265
+                        }
266
+
267
+                        // Check if appinfo/info.xml has the same app ID as well
268
+                        $loadEntities = libxml_disable_entity_loader(false);
269
+                        $xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
270
+                        libxml_disable_entity_loader($loadEntities);
271
+                        if((string)$xml->id !== $appId) {
272
+                            throw new \Exception(
273
+                                sprintf(
274
+                                    'App for id %s has a wrong app ID in info.xml: %s',
275
+                                    $appId,
276
+                                    (string)$xml->id
277
+                                )
278
+                            );
279
+                        }
280
+
281
+                        // Check if the version is lower than before
282
+                        $currentVersion = OC_App::getAppVersion($appId);
283
+                        $newVersion = (string)$xml->version;
284
+                        if(version_compare($currentVersion, $newVersion) === 1) {
285
+                            throw new \Exception(
286
+                                sprintf(
287
+                                    'App for id %s has version %s and tried to update to lower version %s',
288
+                                    $appId,
289
+                                    $currentVersion,
290
+                                    $newVersion
291
+                                )
292
+                            );
293
+                        }
294
+
295
+                        $baseDir = OC_App::getInstallPath() . '/' . $appId;
296
+                        // Remove old app with the ID if existent
297
+                        OC_Helper::rmdirr($baseDir);
298
+                        // Move to app folder
299
+                        if(@mkdir($baseDir)) {
300
+                            $extractDir .= '/' . $folders[0];
301
+                            OC_Helper::copyr($extractDir, $baseDir);
302
+                        }
303
+                        OC_Helper::copyr($extractDir, $baseDir);
304
+                        OC_Helper::rmdirr($extractDir);
305
+                        return;
306
+                    } else {
307
+                        throw new \Exception(
308
+                            sprintf(
309
+                                'Could not extract app with ID %s to %s',
310
+                                $appId,
311
+                                $extractDir
312
+                            )
313
+                        );
314
+                    }
315
+                } else {
316
+                    // Signature does not match
317
+                    throw new \Exception(
318
+                        sprintf(
319
+                            'App with id %s has invalid signature',
320
+                            $appId
321
+                        )
322
+                    );
323
+                }
324
+            }
325
+        }
326
+
327
+        throw new \Exception(
328
+            sprintf(
329
+                'Could not download app %s',
330
+                $appId
331
+            )
332
+        );
333
+    }
334
+
335
+    /**
336
+     * Check if an update for the app is available
337
+     *
338
+     * @param string $appId
339
+     * @param AppFetcher $appFetcher
340
+     * @return string|false false or the version number of the update
341
+     */
342
+    public static function isUpdateAvailable($appId,
343
+                                        AppFetcher $appFetcher) {
344
+        static $isInstanceReadyForUpdates = null;
345
+
346
+        if ($isInstanceReadyForUpdates === null) {
347
+            $installPath = OC_App::getInstallPath();
348
+            if ($installPath === false || $installPath === null) {
349
+                $isInstanceReadyForUpdates = false;
350
+            } else {
351
+                $isInstanceReadyForUpdates = true;
352
+            }
353
+        }
354
+
355
+        if ($isInstanceReadyForUpdates === false) {
356
+            return false;
357
+        }
358
+
359
+        $apps = $appFetcher->get();
360
+        foreach($apps as $app) {
361
+            if($app['id'] === $appId) {
362
+                $currentVersion = OC_App::getAppVersion($appId);
363
+                $newestVersion = $app['releases'][0]['version'];
364
+                if (version_compare($newestVersion, $currentVersion, '>')) {
365
+                    return $newestVersion;
366
+                } else {
367
+                    return false;
368
+                }
369
+            }
370
+        }
371
+
372
+        return false;
373
+    }
374
+
375
+    /**
376
+     * Check if app is already downloaded
377
+     * @param string $name name of the application to remove
378
+     * @return boolean
379
+     *
380
+     * The function will check if the app is already downloaded in the apps repository
381
+     */
382
+    public function isDownloaded($name) {
383
+        foreach(\OC::$APPSROOTS as $dir) {
384
+            $dirToTest  = $dir['path'];
385
+            $dirToTest .= '/';
386
+            $dirToTest .= $name;
387
+            $dirToTest .= '/';
388
+
389
+            if (is_dir($dirToTest)) {
390
+                return true;
391
+            }
392
+        }
393
+
394
+        return false;
395
+    }
396
+
397
+    /**
398
+     * Removes an app
399
+     * @param string $appId ID of the application to remove
400
+     * @return boolean
401
+     *
402
+     *
403
+     * This function works as follows
404
+     *   -# call uninstall repair steps
405
+     *   -# removing the files
406
+     *
407
+     * The function will not delete preferences, tables and the configuration,
408
+     * this has to be done by the function oc_app_uninstall().
409
+     */
410
+    public function removeApp($appId) {
411
+        if($this->isDownloaded( $appId )) {
412
+            $appDir = OC_App::getInstallPath() . '/' . $appId;
413
+            OC_Helper::rmdirr($appDir);
414
+            return true;
415
+        }else{
416
+            \OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR);
417
+
418
+            return false;
419
+        }
420
+
421
+    }
422
+
423
+    /**
424
+     * Installs shipped apps
425
+     *
426
+     * This function installs all apps found in the 'apps' directory that should be enabled by default;
427
+     * @param bool $softErrors When updating we ignore errors and simply log them, better to have a
428
+     *                         working ownCloud at the end instead of an aborted update.
429
+     * @return array Array of error messages (appid => Exception)
430
+     */
431
+    public static function installShippedApps($softErrors = false) {
432
+        $errors = [];
433
+        foreach(\OC::$APPSROOTS as $app_dir) {
434
+            if($dir = opendir( $app_dir['path'] )) {
435
+                while( false !== ( $filename = readdir( $dir ))) {
436
+                    if( substr( $filename, 0, 1 ) != '.' and is_dir($app_dir['path']."/$filename") ) {
437
+                        if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) {
438
+                            if(!Installer::isInstalled($filename)) {
439
+                                $info=OC_App::getAppInfo($filename);
440
+                                $enabled = isset($info['default_enable']);
441
+                                if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps()))
442
+                                      && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') {
443
+                                    if ($softErrors) {
444
+                                        try {
445
+                                            Installer::installShippedApp($filename);
446
+                                        } catch (HintException $e) {
447
+                                            if ($e->getPrevious() instanceof TableExistsException) {
448
+                                                $errors[$filename] = $e;
449
+                                                continue;
450
+                                            }
451
+                                            throw $e;
452
+                                        }
453
+                                    } else {
454
+                                        Installer::installShippedApp($filename);
455
+                                    }
456
+                                    \OC::$server->getConfig()->setAppValue($filename, 'enabled', 'yes');
457
+                                }
458
+                            }
459
+                        }
460
+                    }
461
+                }
462
+                closedir( $dir );
463
+            }
464
+        }
465
+
466
+        return $errors;
467
+    }
468
+
469
+    /**
470
+     * install an app already placed in the app folder
471
+     * @param string $app id of the app to install
472
+     * @return integer
473
+     */
474
+    public static function installShippedApp($app) {
475
+        //install the database
476
+        $appPath = OC_App::getAppPath($app);
477
+        if(is_file("$appPath/appinfo/database.xml")) {
478
+            try {
479
+                OC_DB::createDbFromStructure("$appPath/appinfo/database.xml");
480
+            } catch (TableExistsException $e) {
481
+                throw new HintException(
482
+                    'Failed to enable app ' . $app,
483
+                    'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer">support channels</a>.',
484
+                    0, $e
485
+                );
486
+            }
487
+        }
488
+
489
+        //run appinfo/install.php
490
+        \OC_App::registerAutoloading($app, $appPath);
491
+        self::includeAppScript("$appPath/appinfo/install.php");
492
+
493
+        $info = OC_App::getAppInfo($app);
494
+        if (is_null($info)) {
495
+            return false;
496
+        }
497
+        \OC_App::setupBackgroundJobs($info['background-jobs']);
498
+
499
+        OC_App::executeRepairSteps($app, $info['repair-steps']['install']);
500
+
501
+        $config = \OC::$server->getConfig();
502
+
503
+        $config->setAppValue($app, 'installed_version', OC_App::getAppVersion($app));
504
+        if (array_key_exists('ocsid', $info)) {
505
+            $config->setAppValue($app, 'ocsid', $info['ocsid']);
506
+        }
507
+
508
+        //set remote/public handlers
509
+        foreach($info['remote'] as $name=>$path) {
510
+            $config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
511
+        }
512
+        foreach($info['public'] as $name=>$path) {
513
+            $config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
514
+        }
515
+
516
+        OC_App::setAppTypes($info['id']);
517
+
518
+        if(isset($info['settings']) && is_array($info['settings'])) {
519
+            // requires that autoloading was registered for the app,
520
+            // as happens before running the install.php some lines above
521
+            \OC::$server->getSettingsManager()->setupSettings($info['settings']);
522
+        }
523
+
524
+        return $info['id'];
525
+    }
526
+
527
+    /**
528
+     * check the code of an app with some static code checks
529
+     * @param string $folder the folder of the app to check
530
+     * @return boolean true for app is o.k. and false for app is not o.k.
531
+     */
532
+    public static function checkCode($folder) {
533
+        // is the code checker enabled?
534
+        if(!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) {
535
+            return true;
536
+        }
537
+
538
+        $codeChecker = new CodeChecker(new PrivateCheck(new EmptyCheck()));
539
+        $errors = $codeChecker->analyseFolder(basename($folder), $folder);
540
+
541
+        return empty($errors);
542
+    }
543
+
544
+    /**
545
+     * @param string $script
546
+     */
547
+    private static function includeAppScript($script) {
548
+        if ( file_exists($script) ){
549
+            include $script;
550
+        }
551
+    }
552 552
 }
Please login to merge, or discard this patch.
Spacing   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
94 94
 	 */
95 95
 	public function installApp($appId) {
96 96
 		$app = \OC_App::findAppInDirectories($appId);
97
-		if($app === false) {
97
+		if ($app === false) {
98 98
 			throw new \Exception('App not found in any app directory');
99 99
 		}
100 100
 
@@ -102,7 +102,7 @@  discard block
 block discarded – undo
102 102
 		$info = OC_App::getAppInfo($basedir.'/appinfo/info.xml', true);
103 103
 
104 104
 		//install the database
105
-		if(is_file($basedir.'/appinfo/database.xml')) {
105
+		if (is_file($basedir.'/appinfo/database.xml')) {
106 106
 			if (\OC::$server->getAppConfig()->getValue($info['id'], 'installed_version') === null) {
107 107
 				OC_DB::createDbFromStructure($basedir.'/appinfo/database.xml');
108 108
 			} else {
@@ -113,8 +113,8 @@  discard block
 block discarded – undo
113 113
 		\OC_App::setupBackgroundJobs($info['background-jobs']);
114 114
 
115 115
 		//run appinfo/install.php
116
-		if((!isset($data['noinstall']) or $data['noinstall']==false)) {
117
-			self::includeAppScript($basedir . '/appinfo/install.php');
116
+		if ((!isset($data['noinstall']) or $data['noinstall'] == false)) {
117
+			self::includeAppScript($basedir.'/appinfo/install.php');
118 118
 		}
119 119
 
120 120
 		$appData = OC_App::getAppInfo($appId);
@@ -125,10 +125,10 @@  discard block
 block discarded – undo
125 125
 		\OC::$server->getConfig()->setAppValue($info['id'], 'enabled', 'no');
126 126
 
127 127
 		//set remote/public handlers
128
-		foreach($info['remote'] as $name=>$path) {
128
+		foreach ($info['remote'] as $name=>$path) {
129 129
 			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $info['id'].'/'.$path);
130 130
 		}
131
-		foreach($info['public'] as $name=>$path) {
131
+		foreach ($info['public'] as $name=>$path) {
132 132
 			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $info['id'].'/'.$path);
133 133
 		}
134 134
 
@@ -144,7 +144,7 @@  discard block
 block discarded – undo
144 144
 	 *
145 145
 	 * Checks whether or not an app is installed, i.e. registered in apps table.
146 146
 	 */
147
-	public static function isInstalled( $app ) {
147
+	public static function isInstalled($app) {
148 148
 		return (\OC::$server->getConfig()->getAppValue($app, "installed_version", null) !== null);
149 149
 	}
150 150
 
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
 	 * @return bool
156 156
 	 */
157 157
 	public function updateAppstoreApp($appId) {
158
-		if(self::isUpdateAvailable($appId, $this->appFetcher)) {
158
+		if (self::isUpdateAvailable($appId, $this->appFetcher)) {
159 159
 			try {
160 160
 				$this->downloadApp($appId);
161 161
 			} catch (\Exception $e) {
@@ -179,18 +179,18 @@  discard block
 block discarded – undo
179 179
 		$appId = strtolower($appId);
180 180
 
181 181
 		$apps = $this->appFetcher->get();
182
-		foreach($apps as $app) {
183
-			if($app['id'] === $appId) {
182
+		foreach ($apps as $app) {
183
+			if ($app['id'] === $appId) {
184 184
 				// Load the certificate
185 185
 				$certificate = new X509();
186
-				$certificate->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
186
+				$certificate->loadCA(file_get_contents(__DIR__.'/../../resources/codesigning/root.crt'));
187 187
 				$loadedCertificate = $certificate->loadX509($app['certificate']);
188 188
 
189 189
 				// Verify if the certificate has been revoked
190 190
 				$crl = new X509();
191
-				$crl->loadCA(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crt'));
192
-				$crl->loadCRL(file_get_contents(__DIR__ . '/../../resources/codesigning/root.crl'));
193
-				if($crl->validateSignature() !== true) {
191
+				$crl->loadCA(file_get_contents(__DIR__.'/../../resources/codesigning/root.crt'));
192
+				$crl->loadCRL(file_get_contents(__DIR__.'/../../resources/codesigning/root.crl'));
193
+				if ($crl->validateSignature() !== true) {
194 194
 					throw new \Exception('Could not validate CRL signature');
195 195
 				}
196 196
 				$csn = $loadedCertificate['tbsCertificate']['serialNumber']->toString();
@@ -205,7 +205,7 @@  discard block
 block discarded – undo
205 205
 				}
206 206
 
207 207
 				// Verify if the certificate has been issued by the Nextcloud Code Authority CA
208
-				if($certificate->validateSignature() !== true) {
208
+				if ($certificate->validateSignature() !== true) {
209 209
 					throw new \Exception(
210 210
 						sprintf(
211 211
 							'App with id %s has a certificate not issued by a trusted Code Signing Authority',
@@ -216,7 +216,7 @@  discard block
 block discarded – undo
216 216
 
217 217
 				// Verify if the certificate is issued for the requested app id
218 218
 				$certInfo = openssl_x509_parse($app['certificate']);
219
-				if(!isset($certInfo['subject']['CN'])) {
219
+				if (!isset($certInfo['subject']['CN'])) {
220 220
 					throw new \Exception(
221 221
 						sprintf(
222 222
 							'App with id %s has a cert with no CN',
@@ -224,7 +224,7 @@  discard block
 block discarded – undo
224 224
 						)
225 225
 					);
226 226
 				}
227
-				if($certInfo['subject']['CN'] !== $appId) {
227
+				if ($certInfo['subject']['CN'] !== $appId) {
228 228
 					throw new \Exception(
229 229
 						sprintf(
230 230
 							'App with id %s has a cert issued to %s',
@@ -241,21 +241,21 @@  discard block
 block discarded – undo
241 241
 
242 242
 				// Check if the signature actually matches the downloaded content
243 243
 				$certificate = openssl_get_publickey($app['certificate']);
244
-				$verified = (bool)openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
244
+				$verified = (bool) openssl_verify(file_get_contents($tempFile), base64_decode($app['releases'][0]['signature']), $certificate, OPENSSL_ALGO_SHA512);
245 245
 				openssl_free_key($certificate);
246 246
 
247
-				if($verified === true) {
247
+				if ($verified === true) {
248 248
 					// Seems to match, let's proceed
249 249
 					$extractDir = $this->tempManager->getTemporaryFolder();
250 250
 					$archive = new TAR($tempFile);
251 251
 
252
-					if($archive) {
252
+					if ($archive) {
253 253
 						$archive->extract($extractDir);
254 254
 						$allFiles = scandir($extractDir);
255 255
 						$folders = array_diff($allFiles, ['.', '..']);
256 256
 						$folders = array_values($folders);
257 257
 
258
-						if(count($folders) > 1) {
258
+						if (count($folders) > 1) {
259 259
 							throw new \Exception(
260 260
 								sprintf(
261 261
 									'Extracted app %s has more than 1 folder',
@@ -266,22 +266,22 @@  discard block
 block discarded – undo
266 266
 
267 267
 						// Check if appinfo/info.xml has the same app ID as well
268 268
 						$loadEntities = libxml_disable_entity_loader(false);
269
-						$xml = simplexml_load_file($extractDir . '/' . $folders[0] . '/appinfo/info.xml');
269
+						$xml = simplexml_load_file($extractDir.'/'.$folders[0].'/appinfo/info.xml');
270 270
 						libxml_disable_entity_loader($loadEntities);
271
-						if((string)$xml->id !== $appId) {
271
+						if ((string) $xml->id !== $appId) {
272 272
 							throw new \Exception(
273 273
 								sprintf(
274 274
 									'App for id %s has a wrong app ID in info.xml: %s',
275 275
 									$appId,
276
-									(string)$xml->id
276
+									(string) $xml->id
277 277
 								)
278 278
 							);
279 279
 						}
280 280
 
281 281
 						// Check if the version is lower than before
282 282
 						$currentVersion = OC_App::getAppVersion($appId);
283
-						$newVersion = (string)$xml->version;
284
-						if(version_compare($currentVersion, $newVersion) === 1) {
283
+						$newVersion = (string) $xml->version;
284
+						if (version_compare($currentVersion, $newVersion) === 1) {
285 285
 							throw new \Exception(
286 286
 								sprintf(
287 287
 									'App for id %s has version %s and tried to update to lower version %s',
@@ -292,12 +292,12 @@  discard block
 block discarded – undo
292 292
 							);
293 293
 						}
294 294
 
295
-						$baseDir = OC_App::getInstallPath() . '/' . $appId;
295
+						$baseDir = OC_App::getInstallPath().'/'.$appId;
296 296
 						// Remove old app with the ID if existent
297 297
 						OC_Helper::rmdirr($baseDir);
298 298
 						// Move to app folder
299
-						if(@mkdir($baseDir)) {
300
-							$extractDir .= '/' . $folders[0];
299
+						if (@mkdir($baseDir)) {
300
+							$extractDir .= '/'.$folders[0];
301 301
 							OC_Helper::copyr($extractDir, $baseDir);
302 302
 						}
303 303
 						OC_Helper::copyr($extractDir, $baseDir);
@@ -357,8 +357,8 @@  discard block
 block discarded – undo
357 357
 		}
358 358
 
359 359
 		$apps = $appFetcher->get();
360
-		foreach($apps as $app) {
361
-			if($app['id'] === $appId) {
360
+		foreach ($apps as $app) {
361
+			if ($app['id'] === $appId) {
362 362
 				$currentVersion = OC_App::getAppVersion($appId);
363 363
 				$newestVersion = $app['releases'][0]['version'];
364 364
 				if (version_compare($newestVersion, $currentVersion, '>')) {
@@ -380,7 +380,7 @@  discard block
 block discarded – undo
380 380
 	 * The function will check if the app is already downloaded in the apps repository
381 381
 	 */
382 382
 	public function isDownloaded($name) {
383
-		foreach(\OC::$APPSROOTS as $dir) {
383
+		foreach (\OC::$APPSROOTS as $dir) {
384 384
 			$dirToTest  = $dir['path'];
385 385
 			$dirToTest .= '/';
386 386
 			$dirToTest .= $name;
@@ -408,11 +408,11 @@  discard block
 block discarded – undo
408 408
 	 * this has to be done by the function oc_app_uninstall().
409 409
 	 */
410 410
 	public function removeApp($appId) {
411
-		if($this->isDownloaded( $appId )) {
412
-			$appDir = OC_App::getInstallPath() . '/' . $appId;
411
+		if ($this->isDownloaded($appId)) {
412
+			$appDir = OC_App::getInstallPath().'/'.$appId;
413 413
 			OC_Helper::rmdirr($appDir);
414 414
 			return true;
415
-		}else{
415
+		} else {
416 416
 			\OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR);
417 417
 
418 418
 			return false;
@@ -430,13 +430,13 @@  discard block
 block discarded – undo
430 430
 	 */
431 431
 	public static function installShippedApps($softErrors = false) {
432 432
 		$errors = [];
433
-		foreach(\OC::$APPSROOTS as $app_dir) {
434
-			if($dir = opendir( $app_dir['path'] )) {
435
-				while( false !== ( $filename = readdir( $dir ))) {
436
-					if( substr( $filename, 0, 1 ) != '.' and is_dir($app_dir['path']."/$filename") ) {
437
-						if( file_exists( $app_dir['path']."/$filename/appinfo/info.xml" )) {
438
-							if(!Installer::isInstalled($filename)) {
439
-								$info=OC_App::getAppInfo($filename);
433
+		foreach (\OC::$APPSROOTS as $app_dir) {
434
+			if ($dir = opendir($app_dir['path'])) {
435
+				while (false !== ($filename = readdir($dir))) {
436
+					if (substr($filename, 0, 1) != '.' and is_dir($app_dir['path']."/$filename")) {
437
+						if (file_exists($app_dir['path']."/$filename/appinfo/info.xml")) {
438
+							if (!Installer::isInstalled($filename)) {
439
+								$info = OC_App::getAppInfo($filename);
440 440
 								$enabled = isset($info['default_enable']);
441 441
 								if (($enabled || in_array($filename, \OC::$server->getAppManager()->getAlwaysEnabledApps()))
442 442
 									  && \OC::$server->getConfig()->getAppValue($filename, 'enabled') !== 'no') {
@@ -459,7 +459,7 @@  discard block
 block discarded – undo
459 459
 						}
460 460
 					}
461 461
 				}
462
-				closedir( $dir );
462
+				closedir($dir);
463 463
 			}
464 464
 		}
465 465
 
@@ -474,12 +474,12 @@  discard block
 block discarded – undo
474 474
 	public static function installShippedApp($app) {
475 475
 		//install the database
476 476
 		$appPath = OC_App::getAppPath($app);
477
-		if(is_file("$appPath/appinfo/database.xml")) {
477
+		if (is_file("$appPath/appinfo/database.xml")) {
478 478
 			try {
479 479
 				OC_DB::createDbFromStructure("$appPath/appinfo/database.xml");
480 480
 			} catch (TableExistsException $e) {
481 481
 				throw new HintException(
482
-					'Failed to enable app ' . $app,
482
+					'Failed to enable app '.$app,
483 483
 					'Please ask for help via one of our <a href="https://nextcloud.com/support/" target="_blank" rel="noreferrer">support channels</a>.',
484 484
 					0, $e
485 485
 				);
@@ -506,16 +506,16 @@  discard block
 block discarded – undo
506 506
 		}
507 507
 
508 508
 		//set remote/public handlers
509
-		foreach($info['remote'] as $name=>$path) {
509
+		foreach ($info['remote'] as $name=>$path) {
510 510
 			$config->setAppValue('core', 'remote_'.$name, $app.'/'.$path);
511 511
 		}
512
-		foreach($info['public'] as $name=>$path) {
512
+		foreach ($info['public'] as $name=>$path) {
513 513
 			$config->setAppValue('core', 'public_'.$name, $app.'/'.$path);
514 514
 		}
515 515
 
516 516
 		OC_App::setAppTypes($info['id']);
517 517
 
518
-		if(isset($info['settings']) && is_array($info['settings'])) {
518
+		if (isset($info['settings']) && is_array($info['settings'])) {
519 519
 			// requires that autoloading was registered for the app,
520 520
 			// as happens before running the install.php some lines above
521 521
 			\OC::$server->getSettingsManager()->setupSettings($info['settings']);
@@ -531,7 +531,7 @@  discard block
 block discarded – undo
531 531
 	 */
532 532
 	public static function checkCode($folder) {
533 533
 		// is the code checker enabled?
534
-		if(!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) {
534
+		if (!\OC::$server->getConfig()->getSystemValue('appcodechecker', false)) {
535 535
 			return true;
536 536
 		}
537 537
 
@@ -545,7 +545,7 @@  discard block
 block discarded – undo
545 545
 	 * @param string $script
546 546
 	 */
547 547
 	private static function includeAppScript($script) {
548
-		if ( file_exists($script) ){
548
+		if (file_exists($script)) {
549 549
 			include $script;
550 550
 		}
551 551
 	}
Please login to merge, or discard this patch.
Braces   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -412,7 +412,7 @@
 block discarded – undo
412 412
 			$appDir = OC_App::getInstallPath() . '/' . $appId;
413 413
 			OC_Helper::rmdirr($appDir);
414 414
 			return true;
415
-		}else{
415
+		} else{
416 416
 			\OCP\Util::writeLog('core', 'can\'t remove app '.$appId.'. It is not installed.', \OCP\Util::ERROR);
417 417
 
418 418
 			return false;
Please login to merge, or discard this patch.