Passed
Push — master ( bbb39c...5026d2 )
by Christoph
27:34 queued 12:27
created
apps/files_sharing/lib/Scanner.php 1 patch
Indentation   +43 added lines, -43 removed lines patch added patch discarded remove patch
@@ -32,51 +32,51 @@
 block discarded – undo
32 32
  * Scanner for SharedStorage
33 33
  */
34 34
 class Scanner extends \OC\Files\Cache\Scanner {
35
-	/**
36
-	 * @var \OCA\Files_Sharing\SharedStorage $storage
37
-	 */
38
-	protected $storage;
35
+    /**
36
+     * @var \OCA\Files_Sharing\SharedStorage $storage
37
+     */
38
+    protected $storage;
39 39
 
40
-	private $sourceScanner;
40
+    private $sourceScanner;
41 41
 
42
-	/**
43
-	 * Returns metadata from the shared storage, but
44
-	 * with permissions from the source storage.
45
-	 *
46
-	 * @param string $path path of the file for which to retrieve metadata
47
-	 *
48
-	 * @return array an array of metadata of the file
49
-	 */
50
-	public function getData($path) {
51
-		$data = parent::getData($path);
52
-		if ($data === null) {
53
-			return null;
54
-		}
55
-		$internalPath = $this->storage->getUnjailedPath($path);
56
-		$data['permissions'] = $this->storage->getSourceStorage()->getPermissions($internalPath);
57
-		return $data;
58
-	}
42
+    /**
43
+     * Returns metadata from the shared storage, but
44
+     * with permissions from the source storage.
45
+     *
46
+     * @param string $path path of the file for which to retrieve metadata
47
+     *
48
+     * @return array an array of metadata of the file
49
+     */
50
+    public function getData($path) {
51
+        $data = parent::getData($path);
52
+        if ($data === null) {
53
+            return null;
54
+        }
55
+        $internalPath = $this->storage->getUnjailedPath($path);
56
+        $data['permissions'] = $this->storage->getSourceStorage()->getPermissions($internalPath);
57
+        return $data;
58
+    }
59 59
 
60
-	private function getSourceScanner() {
61
-		if ($this->sourceScanner) {
62
-			return $this->sourceScanner;
63
-		}
64
-		if ($this->storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
65
-			/** @var \OC\Files\Storage\Storage $storage */
66
-			[$storage] = $this->storage->resolvePath('');
67
-			$this->sourceScanner = $storage->getScanner();
68
-			return $this->sourceScanner;
69
-		} else {
70
-			return null;
71
-		}
72
-	}
60
+    private function getSourceScanner() {
61
+        if ($this->sourceScanner) {
62
+            return $this->sourceScanner;
63
+        }
64
+        if ($this->storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
65
+            /** @var \OC\Files\Storage\Storage $storage */
66
+            [$storage] = $this->storage->resolvePath('');
67
+            $this->sourceScanner = $storage->getScanner();
68
+            return $this->sourceScanner;
69
+        } else {
70
+            return null;
71
+        }
72
+    }
73 73
 
74
-	public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true, $data = null) {
75
-		$sourceScanner = $this->getSourceScanner();
76
-		if ($sourceScanner instanceof NoopScanner) {
77
-			return [];
78
-		} else {
79
-			return parent::scanFile($file, $reuseExisting, $parentId, $cacheData, $lock);
80
-		}
81
-	}
74
+    public function scanFile($file, $reuseExisting = 0, $parentId = -1, $cacheData = null, $lock = true, $data = null) {
75
+        $sourceScanner = $this->getSourceScanner();
76
+        if ($sourceScanner instanceof NoopScanner) {
77
+            return [];
78
+        } else {
79
+            return parent::scanFile($file, $reuseExisting, $parentId, $cacheData, $lock);
80
+        }
81
+    }
82 82
 }
Please login to merge, or discard this patch.
apps/files_external/lib/Command/Create.php 2 patches
Indentation   +178 added lines, -178 removed lines patch added patch discarded remove patch
@@ -44,182 +44,182 @@
 block discarded – undo
44 44
 use Symfony\Component\Console\Output\OutputInterface;
45 45
 
46 46
 class Create extends Base {
47
-	/**
48
-	 * @var GlobalStoragesService
49
-	 */
50
-	private $globalService;
51
-
52
-	/**
53
-	 * @var UserStoragesService
54
-	 */
55
-	private $userService;
56
-
57
-	/**
58
-	 * @var IUserManager
59
-	 */
60
-	private $userManager;
61
-
62
-	/** @var BackendService */
63
-	private $backendService;
64
-
65
-	/** @var IUserSession */
66
-	private $userSession;
67
-
68
-	public function __construct(GlobalStoragesService $globalService,
69
-						 UserStoragesService $userService,
70
-						 IUserManager $userManager,
71
-						 IUserSession $userSession,
72
-						 BackendService $backendService
73
-	) {
74
-		parent::__construct();
75
-		$this->globalService = $globalService;
76
-		$this->userService = $userService;
77
-		$this->userManager = $userManager;
78
-		$this->userSession = $userSession;
79
-		$this->backendService = $backendService;
80
-	}
81
-
82
-	protected function configure() {
83
-		$this
84
-			->setName('files_external:create')
85
-			->setDescription('Create a new mount configuration')
86
-			->addOption(
87
-				'user',
88
-				'',
89
-				InputOption::VALUE_OPTIONAL,
90
-				'user to add the mount configuration for, if not set the mount will be added as system mount'
91
-			)
92
-			->addArgument(
93
-				'mount_point',
94
-				InputArgument::REQUIRED,
95
-				'mount point for the new mount'
96
-			)
97
-			->addArgument(
98
-				'storage_backend',
99
-				InputArgument::REQUIRED,
100
-				'storage backend identifier for the new mount, see `occ files_external:backends` for possible values'
101
-			)
102
-			->addArgument(
103
-				'authentication_backend',
104
-				InputArgument::REQUIRED,
105
-				'authentication backend identifier for the new mount, see `occ files_external:backends` for possible values'
106
-			)
107
-			->addOption(
108
-				'config',
109
-				'c',
110
-				InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
111
-				'Mount configuration option in key=value format'
112
-			)
113
-			->addOption(
114
-				'dry',
115
-				'',
116
-				InputOption::VALUE_NONE,
117
-				'Don\'t save the created mount, only list the new mount'
118
-			);
119
-		parent::configure();
120
-	}
121
-
122
-	protected function execute(InputInterface $input, OutputInterface $output): int {
123
-		$user = $input->getOption('user');
124
-		$mountPoint = $input->getArgument('mount_point');
125
-		$storageIdentifier = $input->getArgument('storage_backend');
126
-		$authIdentifier = $input->getArgument('authentication_backend');
127
-		$configInput = $input->getOption('config');
128
-
129
-		$storageBackend = $this->backendService->getBackend($storageIdentifier);
130
-		$authBackend = $this->backendService->getAuthMechanism($authIdentifier);
131
-
132
-		if (!Filesystem::isValidPath($mountPoint)) {
133
-			$output->writeln('<error>Invalid mountpoint "' . $mountPoint . '"</error>');
134
-			return 1;
135
-		}
136
-		if (is_null($storageBackend)) {
137
-			$output->writeln('<error>Storage backend with identifier "' . $storageIdentifier . '" not found (see `occ files_external:backends` for possible values)</error>');
138
-			return 404;
139
-		}
140
-		if (is_null($authBackend)) {
141
-			$output->writeln('<error>Authentication backend with identifier "' . $authIdentifier . '" not found (see `occ files_external:backends` for possible values)</error>');
142
-			return 404;
143
-		}
144
-		$supportedSchemes = array_keys($storageBackend->getAuthSchemes());
145
-		if (!in_array($authBackend->getScheme(), $supportedSchemes)) {
146
-			$output->writeln('<error>Authentication backend "' . $authIdentifier . '" not valid for storage backend "' . $storageIdentifier . '" (see `occ files_external:backends storage ' . $storageIdentifier . '` for possible values)</error>');
147
-			return 1;
148
-		}
149
-
150
-		$config = [];
151
-		foreach ($configInput as $configOption) {
152
-			if (!strpos($configOption, '=')) {
153
-				$output->writeln('<error>Invalid mount configuration option "' . $configOption . '"</error>');
154
-				return 1;
155
-			}
156
-			[$key, $value] = explode('=', $configOption, 2);
157
-			if (!$this->validateParam($key, $value, $storageBackend, $authBackend)) {
158
-				$output->writeln('<error>Unknown configuration for backends "' . $key . '"</error>');
159
-				return 1;
160
-			}
161
-			$config[$key] = $value;
162
-		}
163
-
164
-		$mount = new StorageConfig();
165
-		$mount->setMountPoint($mountPoint);
166
-		$mount->setBackend($storageBackend);
167
-		$mount->setAuthMechanism($authBackend);
168
-		$mount->setBackendOptions($config);
169
-
170
-		if ($user) {
171
-			if (!$this->userManager->userExists($user)) {
172
-				$output->writeln('<error>User "' . $user . '" not found</error>');
173
-				return 1;
174
-			}
175
-			$mount->setApplicableUsers([$user]);
176
-		}
177
-
178
-		if ($input->getOption('dry')) {
179
-			$this->showMount($user, $mount, $input, $output);
180
-		} else {
181
-			$this->getStorageService($user)->addStorage($mount);
182
-			if ($input->getOption('output') === self::OUTPUT_FORMAT_PLAIN) {
183
-				$output->writeln('<info>Storage created with id ' . $mount->getId() . '</info>');
184
-			} else {
185
-				$output->writeln((string)$mount->getId());
186
-			}
187
-		}
188
-		return 0;
189
-	}
190
-
191
-	private function validateParam($key, &$value, Backend $storageBackend, AuthMechanism $authBackend) {
192
-		$params = array_merge($storageBackend->getParameters(), $authBackend->getParameters());
193
-		foreach ($params as $param) {
194
-			/** @var DefinitionParameter $param */
195
-			if ($param->getName() === $key) {
196
-				if ($param->getType() === DefinitionParameter::VALUE_BOOLEAN) {
197
-					$value = ($value === 'true');
198
-				}
199
-				return true;
200
-			}
201
-		}
202
-		return false;
203
-	}
204
-
205
-	private function showMount($user, StorageConfig $mount, InputInterface $input, OutputInterface $output) {
206
-		$listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
207
-		$listInput = new ArrayInput([], $listCommand->getDefinition());
208
-		$listInput->setOption('output', $input->getOption('output'));
209
-		$listInput->setOption('show-password', true);
210
-		$listCommand->listMounts($user, [$mount], $listInput, $output);
211
-	}
212
-
213
-	protected function getStorageService($userId) {
214
-		if (!empty($userId)) {
215
-			$user = $this->userManager->get($userId);
216
-			if (is_null($user)) {
217
-				throw new NoUserException("user $userId not found");
218
-			}
219
-			$this->userSession->setUser($user);
220
-			return $this->userService;
221
-		} else {
222
-			return $this->globalService;
223
-		}
224
-	}
47
+    /**
48
+     * @var GlobalStoragesService
49
+     */
50
+    private $globalService;
51
+
52
+    /**
53
+     * @var UserStoragesService
54
+     */
55
+    private $userService;
56
+
57
+    /**
58
+     * @var IUserManager
59
+     */
60
+    private $userManager;
61
+
62
+    /** @var BackendService */
63
+    private $backendService;
64
+
65
+    /** @var IUserSession */
66
+    private $userSession;
67
+
68
+    public function __construct(GlobalStoragesService $globalService,
69
+                            UserStoragesService $userService,
70
+                            IUserManager $userManager,
71
+                            IUserSession $userSession,
72
+                            BackendService $backendService
73
+    ) {
74
+        parent::__construct();
75
+        $this->globalService = $globalService;
76
+        $this->userService = $userService;
77
+        $this->userManager = $userManager;
78
+        $this->userSession = $userSession;
79
+        $this->backendService = $backendService;
80
+    }
81
+
82
+    protected function configure() {
83
+        $this
84
+            ->setName('files_external:create')
85
+            ->setDescription('Create a new mount configuration')
86
+            ->addOption(
87
+                'user',
88
+                '',
89
+                InputOption::VALUE_OPTIONAL,
90
+                'user to add the mount configuration for, if not set the mount will be added as system mount'
91
+            )
92
+            ->addArgument(
93
+                'mount_point',
94
+                InputArgument::REQUIRED,
95
+                'mount point for the new mount'
96
+            )
97
+            ->addArgument(
98
+                'storage_backend',
99
+                InputArgument::REQUIRED,
100
+                'storage backend identifier for the new mount, see `occ files_external:backends` for possible values'
101
+            )
102
+            ->addArgument(
103
+                'authentication_backend',
104
+                InputArgument::REQUIRED,
105
+                'authentication backend identifier for the new mount, see `occ files_external:backends` for possible values'
106
+            )
107
+            ->addOption(
108
+                'config',
109
+                'c',
110
+                InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
111
+                'Mount configuration option in key=value format'
112
+            )
113
+            ->addOption(
114
+                'dry',
115
+                '',
116
+                InputOption::VALUE_NONE,
117
+                'Don\'t save the created mount, only list the new mount'
118
+            );
119
+        parent::configure();
120
+    }
121
+
122
+    protected function execute(InputInterface $input, OutputInterface $output): int {
123
+        $user = $input->getOption('user');
124
+        $mountPoint = $input->getArgument('mount_point');
125
+        $storageIdentifier = $input->getArgument('storage_backend');
126
+        $authIdentifier = $input->getArgument('authentication_backend');
127
+        $configInput = $input->getOption('config');
128
+
129
+        $storageBackend = $this->backendService->getBackend($storageIdentifier);
130
+        $authBackend = $this->backendService->getAuthMechanism($authIdentifier);
131
+
132
+        if (!Filesystem::isValidPath($mountPoint)) {
133
+            $output->writeln('<error>Invalid mountpoint "' . $mountPoint . '"</error>');
134
+            return 1;
135
+        }
136
+        if (is_null($storageBackend)) {
137
+            $output->writeln('<error>Storage backend with identifier "' . $storageIdentifier . '" not found (see `occ files_external:backends` for possible values)</error>');
138
+            return 404;
139
+        }
140
+        if (is_null($authBackend)) {
141
+            $output->writeln('<error>Authentication backend with identifier "' . $authIdentifier . '" not found (see `occ files_external:backends` for possible values)</error>');
142
+            return 404;
143
+        }
144
+        $supportedSchemes = array_keys($storageBackend->getAuthSchemes());
145
+        if (!in_array($authBackend->getScheme(), $supportedSchemes)) {
146
+            $output->writeln('<error>Authentication backend "' . $authIdentifier . '" not valid for storage backend "' . $storageIdentifier . '" (see `occ files_external:backends storage ' . $storageIdentifier . '` for possible values)</error>');
147
+            return 1;
148
+        }
149
+
150
+        $config = [];
151
+        foreach ($configInput as $configOption) {
152
+            if (!strpos($configOption, '=')) {
153
+                $output->writeln('<error>Invalid mount configuration option "' . $configOption . '"</error>');
154
+                return 1;
155
+            }
156
+            [$key, $value] = explode('=', $configOption, 2);
157
+            if (!$this->validateParam($key, $value, $storageBackend, $authBackend)) {
158
+                $output->writeln('<error>Unknown configuration for backends "' . $key . '"</error>');
159
+                return 1;
160
+            }
161
+            $config[$key] = $value;
162
+        }
163
+
164
+        $mount = new StorageConfig();
165
+        $mount->setMountPoint($mountPoint);
166
+        $mount->setBackend($storageBackend);
167
+        $mount->setAuthMechanism($authBackend);
168
+        $mount->setBackendOptions($config);
169
+
170
+        if ($user) {
171
+            if (!$this->userManager->userExists($user)) {
172
+                $output->writeln('<error>User "' . $user . '" not found</error>');
173
+                return 1;
174
+            }
175
+            $mount->setApplicableUsers([$user]);
176
+        }
177
+
178
+        if ($input->getOption('dry')) {
179
+            $this->showMount($user, $mount, $input, $output);
180
+        } else {
181
+            $this->getStorageService($user)->addStorage($mount);
182
+            if ($input->getOption('output') === self::OUTPUT_FORMAT_PLAIN) {
183
+                $output->writeln('<info>Storage created with id ' . $mount->getId() . '</info>');
184
+            } else {
185
+                $output->writeln((string)$mount->getId());
186
+            }
187
+        }
188
+        return 0;
189
+    }
190
+
191
+    private function validateParam($key, &$value, Backend $storageBackend, AuthMechanism $authBackend) {
192
+        $params = array_merge($storageBackend->getParameters(), $authBackend->getParameters());
193
+        foreach ($params as $param) {
194
+            /** @var DefinitionParameter $param */
195
+            if ($param->getName() === $key) {
196
+                if ($param->getType() === DefinitionParameter::VALUE_BOOLEAN) {
197
+                    $value = ($value === 'true');
198
+                }
199
+                return true;
200
+            }
201
+        }
202
+        return false;
203
+    }
204
+
205
+    private function showMount($user, StorageConfig $mount, InputInterface $input, OutputInterface $output) {
206
+        $listCommand = new ListCommand($this->globalService, $this->userService, $this->userSession, $this->userManager);
207
+        $listInput = new ArrayInput([], $listCommand->getDefinition());
208
+        $listInput->setOption('output', $input->getOption('output'));
209
+        $listInput->setOption('show-password', true);
210
+        $listCommand->listMounts($user, [$mount], $listInput, $output);
211
+    }
212
+
213
+    protected function getStorageService($userId) {
214
+        if (!empty($userId)) {
215
+            $user = $this->userManager->get($userId);
216
+            if (is_null($user)) {
217
+                throw new NoUserException("user $userId not found");
218
+            }
219
+            $this->userSession->setUser($user);
220
+            return $this->userService;
221
+        } else {
222
+            return $this->globalService;
223
+        }
224
+    }
225 225
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -130,32 +130,32 @@  discard block
 block discarded – undo
130 130
 		$authBackend = $this->backendService->getAuthMechanism($authIdentifier);
131 131
 
132 132
 		if (!Filesystem::isValidPath($mountPoint)) {
133
-			$output->writeln('<error>Invalid mountpoint "' . $mountPoint . '"</error>');
133
+			$output->writeln('<error>Invalid mountpoint "'.$mountPoint.'"</error>');
134 134
 			return 1;
135 135
 		}
136 136
 		if (is_null($storageBackend)) {
137
-			$output->writeln('<error>Storage backend with identifier "' . $storageIdentifier . '" not found (see `occ files_external:backends` for possible values)</error>');
137
+			$output->writeln('<error>Storage backend with identifier "'.$storageIdentifier.'" not found (see `occ files_external:backends` for possible values)</error>');
138 138
 			return 404;
139 139
 		}
140 140
 		if (is_null($authBackend)) {
141
-			$output->writeln('<error>Authentication backend with identifier "' . $authIdentifier . '" not found (see `occ files_external:backends` for possible values)</error>');
141
+			$output->writeln('<error>Authentication backend with identifier "'.$authIdentifier.'" not found (see `occ files_external:backends` for possible values)</error>');
142 142
 			return 404;
143 143
 		}
144 144
 		$supportedSchemes = array_keys($storageBackend->getAuthSchemes());
145 145
 		if (!in_array($authBackend->getScheme(), $supportedSchemes)) {
146
-			$output->writeln('<error>Authentication backend "' . $authIdentifier . '" not valid for storage backend "' . $storageIdentifier . '" (see `occ files_external:backends storage ' . $storageIdentifier . '` for possible values)</error>');
146
+			$output->writeln('<error>Authentication backend "'.$authIdentifier.'" not valid for storage backend "'.$storageIdentifier.'" (see `occ files_external:backends storage '.$storageIdentifier.'` for possible values)</error>');
147 147
 			return 1;
148 148
 		}
149 149
 
150 150
 		$config = [];
151 151
 		foreach ($configInput as $configOption) {
152 152
 			if (!strpos($configOption, '=')) {
153
-				$output->writeln('<error>Invalid mount configuration option "' . $configOption . '"</error>');
153
+				$output->writeln('<error>Invalid mount configuration option "'.$configOption.'"</error>');
154 154
 				return 1;
155 155
 			}
156 156
 			[$key, $value] = explode('=', $configOption, 2);
157 157
 			if (!$this->validateParam($key, $value, $storageBackend, $authBackend)) {
158
-				$output->writeln('<error>Unknown configuration for backends "' . $key . '"</error>');
158
+				$output->writeln('<error>Unknown configuration for backends "'.$key.'"</error>');
159 159
 				return 1;
160 160
 			}
161 161
 			$config[$key] = $value;
@@ -169,7 +169,7 @@  discard block
 block discarded – undo
169 169
 
170 170
 		if ($user) {
171 171
 			if (!$this->userManager->userExists($user)) {
172
-				$output->writeln('<error>User "' . $user . '" not found</error>');
172
+				$output->writeln('<error>User "'.$user.'" not found</error>');
173 173
 				return 1;
174 174
 			}
175 175
 			$mount->setApplicableUsers([$user]);
@@ -180,9 +180,9 @@  discard block
 block discarded – undo
180 180
 		} else {
181 181
 			$this->getStorageService($user)->addStorage($mount);
182 182
 			if ($input->getOption('output') === self::OUTPUT_FORMAT_PLAIN) {
183
-				$output->writeln('<info>Storage created with id ' . $mount->getId() . '</info>');
183
+				$output->writeln('<info>Storage created with id '.$mount->getId().'</info>');
184 184
 			} else {
185
-				$output->writeln((string)$mount->getId());
185
+				$output->writeln((string) $mount->getId());
186 186
 			}
187 187
 		}
188 188
 		return 0;
Please login to merge, or discard this patch.
apps/files_external/lib/Command/Verify.php 2 patches
Indentation   +95 added lines, -95 removed lines patch added patch discarded remove patch
@@ -39,109 +39,109 @@
 block discarded – undo
39 39
 use Symfony\Component\Console\Output\OutputInterface;
40 40
 
41 41
 class Verify extends Base {
42
-	/**
43
-	 * @var GlobalStoragesService
44
-	 */
45
-	protected $globalService;
42
+    /**
43
+     * @var GlobalStoragesService
44
+     */
45
+    protected $globalService;
46 46
 
47
-	public function __construct(GlobalStoragesService $globalService) {
48
-		parent::__construct();
49
-		$this->globalService = $globalService;
50
-	}
47
+    public function __construct(GlobalStoragesService $globalService) {
48
+        parent::__construct();
49
+        $this->globalService = $globalService;
50
+    }
51 51
 
52
-	protected function configure() {
53
-		$this
54
-			->setName('files_external:verify')
55
-			->setDescription('Verify mount configuration')
56
-			->addArgument(
57
-				'mount_id',
58
-				InputArgument::REQUIRED,
59
-				'The id of the mount to check'
60
-			)->addOption(
61
-				'config',
62
-				'c',
63
-				InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
64
-				'Additional config option to set before checking in key=value pairs, required for certain auth backends such as login credentails'
65
-			);
66
-		parent::configure();
67
-	}
52
+    protected function configure() {
53
+        $this
54
+            ->setName('files_external:verify')
55
+            ->setDescription('Verify mount configuration')
56
+            ->addArgument(
57
+                'mount_id',
58
+                InputArgument::REQUIRED,
59
+                'The id of the mount to check'
60
+            )->addOption(
61
+                'config',
62
+                'c',
63
+                InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
64
+                'Additional config option to set before checking in key=value pairs, required for certain auth backends such as login credentails'
65
+            );
66
+        parent::configure();
67
+    }
68 68
 
69
-	protected function execute(InputInterface $input, OutputInterface $output): int {
70
-		$mountId = $input->getArgument('mount_id');
71
-		$configInput = $input->getOption('config');
69
+    protected function execute(InputInterface $input, OutputInterface $output): int {
70
+        $mountId = $input->getArgument('mount_id');
71
+        $configInput = $input->getOption('config');
72 72
 
73
-		try {
74
-			$mount = $this->globalService->getStorage($mountId);
75
-		} catch (NotFoundException $e) {
76
-			$output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
77
-			return 404;
78
-		}
73
+        try {
74
+            $mount = $this->globalService->getStorage($mountId);
75
+        } catch (NotFoundException $e) {
76
+            $output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
77
+            return 404;
78
+        }
79 79
 
80
-		$this->updateStorageStatus($mount, $configInput, $output);
80
+        $this->updateStorageStatus($mount, $configInput, $output);
81 81
 
82
-		$this->writeArrayInOutputFormat($input, $output, [
83
-			'status' => StorageNotAvailableException::getStateCodeName($mount->getStatus()),
84
-			'code' => $mount->getStatus(),
85
-			'message' => $mount->getStatusMessage()
86
-		]);
87
-		return 0;
88
-	}
82
+        $this->writeArrayInOutputFormat($input, $output, [
83
+            'status' => StorageNotAvailableException::getStateCodeName($mount->getStatus()),
84
+            'code' => $mount->getStatus(),
85
+            'message' => $mount->getStatusMessage()
86
+        ]);
87
+        return 0;
88
+    }
89 89
 
90
-	private function manipulateStorageConfig(StorageConfig $storage) {
91
-		/** @var AuthMechanism */
92
-		$authMechanism = $storage->getAuthMechanism();
93
-		$authMechanism->manipulateStorageConfig($storage);
94
-		/** @var Backend */
95
-		$backend = $storage->getBackend();
96
-		$backend->manipulateStorageConfig($storage);
97
-	}
90
+    private function manipulateStorageConfig(StorageConfig $storage) {
91
+        /** @var AuthMechanism */
92
+        $authMechanism = $storage->getAuthMechanism();
93
+        $authMechanism->manipulateStorageConfig($storage);
94
+        /** @var Backend */
95
+        $backend = $storage->getBackend();
96
+        $backend->manipulateStorageConfig($storage);
97
+    }
98 98
 
99
-	private function updateStorageStatus(StorageConfig &$storage, $configInput, OutputInterface $output) {
100
-		try {
101
-			try {
102
-				$this->manipulateStorageConfig($storage);
103
-			} catch (InsufficientDataForMeaningfulAnswerException $e) {
104
-				if (count($configInput) === 0) { // extra config options might solve the error
105
-					throw $e;
106
-				}
107
-			}
99
+    private function updateStorageStatus(StorageConfig &$storage, $configInput, OutputInterface $output) {
100
+        try {
101
+            try {
102
+                $this->manipulateStorageConfig($storage);
103
+            } catch (InsufficientDataForMeaningfulAnswerException $e) {
104
+                if (count($configInput) === 0) { // extra config options might solve the error
105
+                    throw $e;
106
+                }
107
+            }
108 108
 
109
-			foreach ($configInput as $configOption) {
110
-				if (!strpos($configOption, '=')) {
111
-					$output->writeln('<error>Invalid mount configuration option "' . $configOption . '"</error>');
112
-					return;
113
-				}
114
-				[$key, $value] = explode('=', $configOption, 2);
115
-				$storage->setBackendOption($key, $value);
116
-			}
109
+            foreach ($configInput as $configOption) {
110
+                if (!strpos($configOption, '=')) {
111
+                    $output->writeln('<error>Invalid mount configuration option "' . $configOption . '"</error>');
112
+                    return;
113
+                }
114
+                [$key, $value] = explode('=', $configOption, 2);
115
+                $storage->setBackendOption($key, $value);
116
+            }
117 117
 
118
-			/** @var Backend */
119
-			$backend = $storage->getBackend();
120
-			// update status (can be time-consuming)
121
-			$storage->setStatus(
122
-				\OCA\Files_External\MountConfig::getBackendStatus(
123
-					$backend->getStorageClass(),
124
-					$storage->getBackendOptions(),
125
-					false
126
-				)
127
-			);
128
-		} catch (InsufficientDataForMeaningfulAnswerException $e) {
129
-			$status = $e->getCode() ? $e->getCode() : StorageNotAvailableException::STATUS_INDETERMINATE;
130
-			$storage->setStatus(
131
-				$status,
132
-				$e->getMessage()
133
-			);
134
-		} catch (StorageNotAvailableException $e) {
135
-			$storage->setStatus(
136
-				$e->getCode(),
137
-				$e->getMessage()
138
-			);
139
-		} catch (\Exception $e) {
140
-			// FIXME: convert storage exceptions to StorageNotAvailableException
141
-			$storage->setStatus(
142
-				StorageNotAvailableException::STATUS_ERROR,
143
-				get_class($e) . ': ' . $e->getMessage()
144
-			);
145
-		}
146
-	}
118
+            /** @var Backend */
119
+            $backend = $storage->getBackend();
120
+            // update status (can be time-consuming)
121
+            $storage->setStatus(
122
+                \OCA\Files_External\MountConfig::getBackendStatus(
123
+                    $backend->getStorageClass(),
124
+                    $storage->getBackendOptions(),
125
+                    false
126
+                )
127
+            );
128
+        } catch (InsufficientDataForMeaningfulAnswerException $e) {
129
+            $status = $e->getCode() ? $e->getCode() : StorageNotAvailableException::STATUS_INDETERMINATE;
130
+            $storage->setStatus(
131
+                $status,
132
+                $e->getMessage()
133
+            );
134
+        } catch (StorageNotAvailableException $e) {
135
+            $storage->setStatus(
136
+                $e->getCode(),
137
+                $e->getMessage()
138
+            );
139
+        } catch (\Exception $e) {
140
+            // FIXME: convert storage exceptions to StorageNotAvailableException
141
+            $storage->setStatus(
142
+                StorageNotAvailableException::STATUS_ERROR,
143
+                get_class($e) . ': ' . $e->getMessage()
144
+            );
145
+        }
146
+    }
147 147
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -73,7 +73,7 @@  discard block
 block discarded – undo
73 73
 		try {
74 74
 			$mount = $this->globalService->getStorage($mountId);
75 75
 		} catch (NotFoundException $e) {
76
-			$output->writeln('<error>Mount with id "' . $mountId . ' not found, check "occ files_external:list" to get available mounts"</error>');
76
+			$output->writeln('<error>Mount with id "'.$mountId.' not found, check "occ files_external:list" to get available mounts"</error>');
77 77
 			return 404;
78 78
 		}
79 79
 
@@ -108,7 +108,7 @@  discard block
 block discarded – undo
108 108
 
109 109
 			foreach ($configInput as $configOption) {
110 110
 				if (!strpos($configOption, '=')) {
111
-					$output->writeln('<error>Invalid mount configuration option "' . $configOption . '"</error>');
111
+					$output->writeln('<error>Invalid mount configuration option "'.$configOption.'"</error>');
112 112
 					return;
113 113
 				}
114 114
 				[$key, $value] = explode('=', $configOption, 2);
@@ -140,7 +140,7 @@  discard block
 block discarded – undo
140 140
 			// FIXME: convert storage exceptions to StorageNotAvailableException
141 141
 			$storage->setStatus(
142 142
 				StorageNotAvailableException::STATUS_ERROR,
143
-				get_class($e) . ': ' . $e->getMessage()
143
+				get_class($e).': '.$e->getMessage()
144 144
 			);
145 145
 		}
146 146
 	}
Please login to merge, or discard this patch.
apps/encryption/lib/Crypto/EncryptAll.php 1 patch
Indentation   +430 added lines, -430 removed lines patch added patch discarded remove patch
@@ -47,434 +47,434 @@
 block discarded – undo
47 47
 
48 48
 class EncryptAll {
49 49
 
50
-	/** @var Setup */
51
-	protected $userSetup;
52
-
53
-	/** @var IUserManager */
54
-	protected $userManager;
55
-
56
-	/** @var View */
57
-	protected $rootView;
58
-
59
-	/** @var KeyManager */
60
-	protected $keyManager;
61
-
62
-	/** @var Util */
63
-	protected $util;
64
-
65
-	/** @var array  */
66
-	protected $userPasswords;
67
-
68
-	/** @var  IConfig */
69
-	protected $config;
70
-
71
-	/** @var IMailer */
72
-	protected $mailer;
73
-
74
-	/** @var  IL10N */
75
-	protected $l;
76
-
77
-	/** @var  QuestionHelper */
78
-	protected $questionHelper;
79
-
80
-	/** @var  OutputInterface */
81
-	protected $output;
82
-
83
-	/** @var  InputInterface */
84
-	protected $input;
85
-
86
-	/** @var ISecureRandom */
87
-	protected $secureRandom;
88
-
89
-	/**
90
-	 * @param Setup $userSetup
91
-	 * @param IUserManager $userManager
92
-	 * @param View $rootView
93
-	 * @param KeyManager $keyManager
94
-	 * @param Util $util
95
-	 * @param IConfig $config
96
-	 * @param IMailer $mailer
97
-	 * @param IL10N $l
98
-	 * @param QuestionHelper $questionHelper
99
-	 * @param ISecureRandom $secureRandom
100
-	 */
101
-	public function __construct(
102
-		Setup $userSetup,
103
-		IUserManager $userManager,
104
-		View $rootView,
105
-		KeyManager $keyManager,
106
-		Util $util,
107
-		IConfig $config,
108
-		IMailer $mailer,
109
-		IL10N $l,
110
-		QuestionHelper $questionHelper,
111
-		ISecureRandom $secureRandom
112
-	) {
113
-		$this->userSetup = $userSetup;
114
-		$this->userManager = $userManager;
115
-		$this->rootView = $rootView;
116
-		$this->keyManager = $keyManager;
117
-		$this->util = $util;
118
-		$this->config = $config;
119
-		$this->mailer = $mailer;
120
-		$this->l = $l;
121
-		$this->questionHelper = $questionHelper;
122
-		$this->secureRandom = $secureRandom;
123
-		// store one time passwords for the users
124
-		$this->userPasswords = [];
125
-	}
126
-
127
-	/**
128
-	 * start to encrypt all files
129
-	 *
130
-	 * @param InputInterface $input
131
-	 * @param OutputInterface $output
132
-	 */
133
-	public function encryptAll(InputInterface $input, OutputInterface $output) {
134
-		$this->input = $input;
135
-		$this->output = $output;
136
-
137
-		$headline = 'Encrypt all files with the ' . Encryption::DISPLAY_NAME;
138
-		$this->output->writeln("\n");
139
-		$this->output->writeln($headline);
140
-		$this->output->writeln(str_pad('', strlen($headline), '='));
141
-		$this->output->writeln("\n");
142
-
143
-		if ($this->util->isMasterKeyEnabled()) {
144
-			$this->output->writeln('Use master key to encrypt all files.');
145
-			$this->keyManager->validateMasterKey();
146
-		} else {
147
-			//create private/public keys for each user and store the private key password
148
-			$this->output->writeln('Create key-pair for every user');
149
-			$this->output->writeln('------------------------------');
150
-			$this->output->writeln('');
151
-			$this->output->writeln('This module will encrypt all files in the users files folder initially.');
152
-			$this->output->writeln('Already existing versions and files in the trash bin will not be encrypted.');
153
-			$this->output->writeln('');
154
-			$this->createKeyPairs();
155
-		}
156
-
157
-
158
-		// output generated encryption key passwords
159
-		if ($this->util->isMasterKeyEnabled() === false) {
160
-			//send-out or display password list and write it to a file
161
-			$this->output->writeln("\n");
162
-			$this->output->writeln('Generated encryption key passwords');
163
-			$this->output->writeln('----------------------------------');
164
-			$this->output->writeln('');
165
-			$this->outputPasswords();
166
-		}
167
-
168
-		//setup users file system and encrypt all files one by one (take should encrypt setting of storage into account)
169
-		$this->output->writeln("\n");
170
-		$this->output->writeln('Start to encrypt users files');
171
-		$this->output->writeln('----------------------------');
172
-		$this->output->writeln('');
173
-		$this->encryptAllUsersFiles();
174
-		$this->output->writeln("\n");
175
-	}
176
-
177
-	/**
178
-	 * create key-pair for every user
179
-	 */
180
-	protected function createKeyPairs() {
181
-		$this->output->writeln("\n");
182
-		$progress = new ProgressBar($this->output);
183
-		$progress->setFormat(" %message% \n [%bar%]");
184
-		$progress->start();
185
-
186
-		foreach ($this->userManager->getBackends() as $backend) {
187
-			$limit = 500;
188
-			$offset = 0;
189
-			do {
190
-				$users = $backend->getUsers('', $limit, $offset);
191
-				foreach ($users as $user) {
192
-					if ($this->keyManager->userHasKeys($user) === false) {
193
-						$progress->setMessage('Create key-pair for ' . $user);
194
-						$progress->advance();
195
-						$this->setupUserFS($user);
196
-						$password = $this->generateOneTimePassword($user);
197
-						$this->userSetup->setupUser($user, $password);
198
-					} else {
199
-						// users which already have a key-pair will be stored with a
200
-						// empty password and filtered out later
201
-						$this->userPasswords[$user] = '';
202
-					}
203
-				}
204
-				$offset += $limit;
205
-			} while (count($users) >= $limit);
206
-		}
207
-
208
-		$progress->setMessage('Key-pair created for all users');
209
-		$progress->finish();
210
-	}
211
-
212
-	/**
213
-	 * iterate over all user and encrypt their files
214
-	 */
215
-	protected function encryptAllUsersFiles() {
216
-		$this->output->writeln("\n");
217
-		$progress = new ProgressBar($this->output);
218
-		$progress->setFormat(" %message% \n [%bar%]");
219
-		$progress->start();
220
-		$numberOfUsers = count($this->userPasswords);
221
-		$userNo = 1;
222
-		if ($this->util->isMasterKeyEnabled()) {
223
-			$this->encryptAllUserFilesWithMasterKey($progress);
224
-		} else {
225
-			foreach ($this->userPasswords as $uid => $password) {
226
-				$userCount = "$uid ($userNo of $numberOfUsers)";
227
-				$this->encryptUsersFiles($uid, $progress, $userCount);
228
-				$userNo++;
229
-			}
230
-		}
231
-		$progress->setMessage("all files encrypted");
232
-		$progress->finish();
233
-	}
234
-
235
-	/**
236
-	 * encrypt all user files with the master key
237
-	 *
238
-	 * @param ProgressBar $progress
239
-	 */
240
-	protected function encryptAllUserFilesWithMasterKey(ProgressBar $progress) {
241
-		$userNo = 1;
242
-		foreach ($this->userManager->getBackends() as $backend) {
243
-			$limit = 500;
244
-			$offset = 0;
245
-			do {
246
-				$users = $backend->getUsers('', $limit, $offset);
247
-				foreach ($users as $user) {
248
-					$userCount = "$user ($userNo)";
249
-					$this->encryptUsersFiles($user, $progress, $userCount);
250
-					$userNo++;
251
-				}
252
-				$offset += $limit;
253
-			} while (count($users) >= $limit);
254
-		}
255
-	}
256
-
257
-	/**
258
-	 * encrypt files from the given user
259
-	 *
260
-	 * @param string $uid
261
-	 * @param ProgressBar $progress
262
-	 * @param string $userCount
263
-	 */
264
-	protected function encryptUsersFiles($uid, ProgressBar $progress, $userCount) {
265
-		$this->setupUserFS($uid);
266
-		$directories = [];
267
-		$directories[] = '/' . $uid . '/files';
268
-
269
-		while ($root = array_pop($directories)) {
270
-			$content = $this->rootView->getDirectoryContent($root);
271
-			foreach ($content as $file) {
272
-				$path = $root . '/' . $file['name'];
273
-				if ($this->rootView->is_dir($path)) {
274
-					$directories[] = $path;
275
-					continue;
276
-				} else {
277
-					$progress->setMessage("encrypt files for user $userCount: $path");
278
-					$progress->advance();
279
-					if ($this->encryptFile($path) === false) {
280
-						$progress->setMessage("encrypt files for user $userCount: $path (already encrypted)");
281
-						$progress->advance();
282
-					}
283
-				}
284
-			}
285
-		}
286
-	}
287
-
288
-	/**
289
-	 * encrypt file
290
-	 *
291
-	 * @param string $path
292
-	 * @return bool
293
-	 */
294
-	protected function encryptFile($path) {
295
-
296
-		// skip already encrypted files
297
-		$fileInfo = $this->rootView->getFileInfo($path);
298
-		if ($fileInfo !== false && $fileInfo->isEncrypted()) {
299
-			return true;
300
-		}
301
-
302
-		$source = $path;
303
-		$target = $path . '.encrypted.' . time();
304
-
305
-		try {
306
-			$this->rootView->copy($source, $target);
307
-			$this->rootView->rename($target, $source);
308
-		} catch (DecryptionFailedException $e) {
309
-			if ($this->rootView->file_exists($target)) {
310
-				$this->rootView->unlink($target);
311
-			}
312
-			return false;
313
-		}
314
-
315
-		return true;
316
-	}
317
-
318
-	/**
319
-	 * output one-time encryption passwords
320
-	 */
321
-	protected function outputPasswords() {
322
-		$table = new Table($this->output);
323
-		$table->setHeaders(['Username', 'Private key password']);
324
-
325
-		//create rows
326
-		$newPasswords = [];
327
-		$unchangedPasswords = [];
328
-		foreach ($this->userPasswords as $uid => $password) {
329
-			if (empty($password)) {
330
-				$unchangedPasswords[] = $uid;
331
-			} else {
332
-				$newPasswords[] = [$uid, $password];
333
-			}
334
-		}
335
-
336
-		if (empty($newPasswords)) {
337
-			$this->output->writeln("\nAll users already had a key-pair, no further action needed.\n");
338
-			return;
339
-		}
340
-
341
-		$table->setRows($newPasswords);
342
-		$table->render();
343
-
344
-		if (!empty($unchangedPasswords)) {
345
-			$this->output->writeln("\nThe following users already had a key-pair which was reused without setting a new password:\n");
346
-			foreach ($unchangedPasswords as $uid) {
347
-				$this->output->writeln("    $uid");
348
-			}
349
-		}
350
-
351
-		$this->writePasswordsToFile($newPasswords);
352
-
353
-		$this->output->writeln('');
354
-		$question = new ConfirmationQuestion('Do you want to send the passwords directly to the users by mail? (y/n) ', false);
355
-		if ($this->questionHelper->ask($this->input, $this->output, $question)) {
356
-			$this->sendPasswordsByMail();
357
-		}
358
-	}
359
-
360
-	/**
361
-	 * write one-time encryption passwords to a csv file
362
-	 *
363
-	 * @param array $passwords
364
-	 */
365
-	protected function writePasswordsToFile(array $passwords) {
366
-		$fp = $this->rootView->fopen('oneTimeEncryptionPasswords.csv', 'w');
367
-		foreach ($passwords as $pwd) {
368
-			fputcsv($fp, $pwd);
369
-		}
370
-		fclose($fp);
371
-		$this->output->writeln("\n");
372
-		$this->output->writeln('A list of all newly created passwords was written to data/oneTimeEncryptionPasswords.csv');
373
-		$this->output->writeln('');
374
-		$this->output->writeln('Each of these users need to login to the web interface, go to the');
375
-		$this->output->writeln('personal settings section "basic encryption module" and');
376
-		$this->output->writeln('update the private key password to match the login password again by');
377
-		$this->output->writeln('entering the one-time password into the "old log-in password" field');
378
-		$this->output->writeln('and their current login password');
379
-	}
380
-
381
-	/**
382
-	 * setup user file system
383
-	 *
384
-	 * @param string $uid
385
-	 */
386
-	protected function setupUserFS($uid) {
387
-		\OC_Util::tearDownFS();
388
-		\OC_Util::setupFS($uid);
389
-	}
390
-
391
-	/**
392
-	 * generate one time password for the user and store it in a array
393
-	 *
394
-	 * @param string $uid
395
-	 * @return string password
396
-	 */
397
-	protected function generateOneTimePassword($uid) {
398
-		$password = $this->secureRandom->generate(8);
399
-		$this->userPasswords[$uid] = $password;
400
-		return $password;
401
-	}
402
-
403
-	/**
404
-	 * send encryption key passwords to the users by mail
405
-	 */
406
-	protected function sendPasswordsByMail() {
407
-		$noMail = [];
408
-
409
-		$this->output->writeln('');
410
-		$progress = new ProgressBar($this->output, count($this->userPasswords));
411
-		$progress->start();
412
-
413
-		foreach ($this->userPasswords as $uid => $password) {
414
-			$progress->advance();
415
-			if (!empty($password)) {
416
-				$recipient = $this->userManager->get($uid);
417
-				$recipientDisplayName = $recipient->getDisplayName();
418
-				$to = $recipient->getEMailAddress();
419
-
420
-				if ($to === '' || $to === null) {
421
-					$noMail[] = $uid;
422
-					continue;
423
-				}
424
-
425
-				$subject = $this->l->t('one-time password for server-side-encryption');
426
-				[$htmlBody, $textBody] = $this->createMailBody($password);
427
-
428
-				// send it out now
429
-				try {
430
-					$message = $this->mailer->createMessage();
431
-					$message->setSubject($subject);
432
-					$message->setTo([$to => $recipientDisplayName]);
433
-					$message->setHtmlBody($htmlBody);
434
-					$message->setPlainBody($textBody);
435
-					$message->setFrom([
436
-						\OCP\Util::getDefaultEmailAddress('admin-noreply')
437
-					]);
438
-
439
-					$this->mailer->send($message);
440
-				} catch (\Exception $e) {
441
-					$noMail[] = $uid;
442
-				}
443
-			}
444
-		}
445
-
446
-		$progress->finish();
447
-
448
-		if (empty($noMail)) {
449
-			$this->output->writeln("\n\nPassword successfully send to all users");
450
-		} else {
451
-			$table = new Table($this->output);
452
-			$table->setHeaders(['Username', 'Private key password']);
453
-			$this->output->writeln("\n\nCould not send password to following users:\n");
454
-			$rows = [];
455
-			foreach ($noMail as $uid) {
456
-				$rows[] = [$uid, $this->userPasswords[$uid]];
457
-			}
458
-			$table->setRows($rows);
459
-			$table->render();
460
-		}
461
-	}
462
-
463
-	/**
464
-	 * create mail body for plain text and html mail
465
-	 *
466
-	 * @param string $password one-time encryption password
467
-	 * @return array an array of the html mail body and the plain text mail body
468
-	 */
469
-	protected function createMailBody($password) {
470
-		$html = new \OC_Template("encryption", "mail", "");
471
-		$html->assign('password', $password);
472
-		$htmlMail = $html->fetchPage();
473
-
474
-		$plainText = new \OC_Template("encryption", "altmail", "");
475
-		$plainText->assign('password', $password);
476
-		$plainTextMail = $plainText->fetchPage();
477
-
478
-		return [$htmlMail, $plainTextMail];
479
-	}
50
+    /** @var Setup */
51
+    protected $userSetup;
52
+
53
+    /** @var IUserManager */
54
+    protected $userManager;
55
+
56
+    /** @var View */
57
+    protected $rootView;
58
+
59
+    /** @var KeyManager */
60
+    protected $keyManager;
61
+
62
+    /** @var Util */
63
+    protected $util;
64
+
65
+    /** @var array  */
66
+    protected $userPasswords;
67
+
68
+    /** @var  IConfig */
69
+    protected $config;
70
+
71
+    /** @var IMailer */
72
+    protected $mailer;
73
+
74
+    /** @var  IL10N */
75
+    protected $l;
76
+
77
+    /** @var  QuestionHelper */
78
+    protected $questionHelper;
79
+
80
+    /** @var  OutputInterface */
81
+    protected $output;
82
+
83
+    /** @var  InputInterface */
84
+    protected $input;
85
+
86
+    /** @var ISecureRandom */
87
+    protected $secureRandom;
88
+
89
+    /**
90
+     * @param Setup $userSetup
91
+     * @param IUserManager $userManager
92
+     * @param View $rootView
93
+     * @param KeyManager $keyManager
94
+     * @param Util $util
95
+     * @param IConfig $config
96
+     * @param IMailer $mailer
97
+     * @param IL10N $l
98
+     * @param QuestionHelper $questionHelper
99
+     * @param ISecureRandom $secureRandom
100
+     */
101
+    public function __construct(
102
+        Setup $userSetup,
103
+        IUserManager $userManager,
104
+        View $rootView,
105
+        KeyManager $keyManager,
106
+        Util $util,
107
+        IConfig $config,
108
+        IMailer $mailer,
109
+        IL10N $l,
110
+        QuestionHelper $questionHelper,
111
+        ISecureRandom $secureRandom
112
+    ) {
113
+        $this->userSetup = $userSetup;
114
+        $this->userManager = $userManager;
115
+        $this->rootView = $rootView;
116
+        $this->keyManager = $keyManager;
117
+        $this->util = $util;
118
+        $this->config = $config;
119
+        $this->mailer = $mailer;
120
+        $this->l = $l;
121
+        $this->questionHelper = $questionHelper;
122
+        $this->secureRandom = $secureRandom;
123
+        // store one time passwords for the users
124
+        $this->userPasswords = [];
125
+    }
126
+
127
+    /**
128
+     * start to encrypt all files
129
+     *
130
+     * @param InputInterface $input
131
+     * @param OutputInterface $output
132
+     */
133
+    public function encryptAll(InputInterface $input, OutputInterface $output) {
134
+        $this->input = $input;
135
+        $this->output = $output;
136
+
137
+        $headline = 'Encrypt all files with the ' . Encryption::DISPLAY_NAME;
138
+        $this->output->writeln("\n");
139
+        $this->output->writeln($headline);
140
+        $this->output->writeln(str_pad('', strlen($headline), '='));
141
+        $this->output->writeln("\n");
142
+
143
+        if ($this->util->isMasterKeyEnabled()) {
144
+            $this->output->writeln('Use master key to encrypt all files.');
145
+            $this->keyManager->validateMasterKey();
146
+        } else {
147
+            //create private/public keys for each user and store the private key password
148
+            $this->output->writeln('Create key-pair for every user');
149
+            $this->output->writeln('------------------------------');
150
+            $this->output->writeln('');
151
+            $this->output->writeln('This module will encrypt all files in the users files folder initially.');
152
+            $this->output->writeln('Already existing versions and files in the trash bin will not be encrypted.');
153
+            $this->output->writeln('');
154
+            $this->createKeyPairs();
155
+        }
156
+
157
+
158
+        // output generated encryption key passwords
159
+        if ($this->util->isMasterKeyEnabled() === false) {
160
+            //send-out or display password list and write it to a file
161
+            $this->output->writeln("\n");
162
+            $this->output->writeln('Generated encryption key passwords');
163
+            $this->output->writeln('----------------------------------');
164
+            $this->output->writeln('');
165
+            $this->outputPasswords();
166
+        }
167
+
168
+        //setup users file system and encrypt all files one by one (take should encrypt setting of storage into account)
169
+        $this->output->writeln("\n");
170
+        $this->output->writeln('Start to encrypt users files');
171
+        $this->output->writeln('----------------------------');
172
+        $this->output->writeln('');
173
+        $this->encryptAllUsersFiles();
174
+        $this->output->writeln("\n");
175
+    }
176
+
177
+    /**
178
+     * create key-pair for every user
179
+     */
180
+    protected function createKeyPairs() {
181
+        $this->output->writeln("\n");
182
+        $progress = new ProgressBar($this->output);
183
+        $progress->setFormat(" %message% \n [%bar%]");
184
+        $progress->start();
185
+
186
+        foreach ($this->userManager->getBackends() as $backend) {
187
+            $limit = 500;
188
+            $offset = 0;
189
+            do {
190
+                $users = $backend->getUsers('', $limit, $offset);
191
+                foreach ($users as $user) {
192
+                    if ($this->keyManager->userHasKeys($user) === false) {
193
+                        $progress->setMessage('Create key-pair for ' . $user);
194
+                        $progress->advance();
195
+                        $this->setupUserFS($user);
196
+                        $password = $this->generateOneTimePassword($user);
197
+                        $this->userSetup->setupUser($user, $password);
198
+                    } else {
199
+                        // users which already have a key-pair will be stored with a
200
+                        // empty password and filtered out later
201
+                        $this->userPasswords[$user] = '';
202
+                    }
203
+                }
204
+                $offset += $limit;
205
+            } while (count($users) >= $limit);
206
+        }
207
+
208
+        $progress->setMessage('Key-pair created for all users');
209
+        $progress->finish();
210
+    }
211
+
212
+    /**
213
+     * iterate over all user and encrypt their files
214
+     */
215
+    protected function encryptAllUsersFiles() {
216
+        $this->output->writeln("\n");
217
+        $progress = new ProgressBar($this->output);
218
+        $progress->setFormat(" %message% \n [%bar%]");
219
+        $progress->start();
220
+        $numberOfUsers = count($this->userPasswords);
221
+        $userNo = 1;
222
+        if ($this->util->isMasterKeyEnabled()) {
223
+            $this->encryptAllUserFilesWithMasterKey($progress);
224
+        } else {
225
+            foreach ($this->userPasswords as $uid => $password) {
226
+                $userCount = "$uid ($userNo of $numberOfUsers)";
227
+                $this->encryptUsersFiles($uid, $progress, $userCount);
228
+                $userNo++;
229
+            }
230
+        }
231
+        $progress->setMessage("all files encrypted");
232
+        $progress->finish();
233
+    }
234
+
235
+    /**
236
+     * encrypt all user files with the master key
237
+     *
238
+     * @param ProgressBar $progress
239
+     */
240
+    protected function encryptAllUserFilesWithMasterKey(ProgressBar $progress) {
241
+        $userNo = 1;
242
+        foreach ($this->userManager->getBackends() as $backend) {
243
+            $limit = 500;
244
+            $offset = 0;
245
+            do {
246
+                $users = $backend->getUsers('', $limit, $offset);
247
+                foreach ($users as $user) {
248
+                    $userCount = "$user ($userNo)";
249
+                    $this->encryptUsersFiles($user, $progress, $userCount);
250
+                    $userNo++;
251
+                }
252
+                $offset += $limit;
253
+            } while (count($users) >= $limit);
254
+        }
255
+    }
256
+
257
+    /**
258
+     * encrypt files from the given user
259
+     *
260
+     * @param string $uid
261
+     * @param ProgressBar $progress
262
+     * @param string $userCount
263
+     */
264
+    protected function encryptUsersFiles($uid, ProgressBar $progress, $userCount) {
265
+        $this->setupUserFS($uid);
266
+        $directories = [];
267
+        $directories[] = '/' . $uid . '/files';
268
+
269
+        while ($root = array_pop($directories)) {
270
+            $content = $this->rootView->getDirectoryContent($root);
271
+            foreach ($content as $file) {
272
+                $path = $root . '/' . $file['name'];
273
+                if ($this->rootView->is_dir($path)) {
274
+                    $directories[] = $path;
275
+                    continue;
276
+                } else {
277
+                    $progress->setMessage("encrypt files for user $userCount: $path");
278
+                    $progress->advance();
279
+                    if ($this->encryptFile($path) === false) {
280
+                        $progress->setMessage("encrypt files for user $userCount: $path (already encrypted)");
281
+                        $progress->advance();
282
+                    }
283
+                }
284
+            }
285
+        }
286
+    }
287
+
288
+    /**
289
+     * encrypt file
290
+     *
291
+     * @param string $path
292
+     * @return bool
293
+     */
294
+    protected function encryptFile($path) {
295
+
296
+        // skip already encrypted files
297
+        $fileInfo = $this->rootView->getFileInfo($path);
298
+        if ($fileInfo !== false && $fileInfo->isEncrypted()) {
299
+            return true;
300
+        }
301
+
302
+        $source = $path;
303
+        $target = $path . '.encrypted.' . time();
304
+
305
+        try {
306
+            $this->rootView->copy($source, $target);
307
+            $this->rootView->rename($target, $source);
308
+        } catch (DecryptionFailedException $e) {
309
+            if ($this->rootView->file_exists($target)) {
310
+                $this->rootView->unlink($target);
311
+            }
312
+            return false;
313
+        }
314
+
315
+        return true;
316
+    }
317
+
318
+    /**
319
+     * output one-time encryption passwords
320
+     */
321
+    protected function outputPasswords() {
322
+        $table = new Table($this->output);
323
+        $table->setHeaders(['Username', 'Private key password']);
324
+
325
+        //create rows
326
+        $newPasswords = [];
327
+        $unchangedPasswords = [];
328
+        foreach ($this->userPasswords as $uid => $password) {
329
+            if (empty($password)) {
330
+                $unchangedPasswords[] = $uid;
331
+            } else {
332
+                $newPasswords[] = [$uid, $password];
333
+            }
334
+        }
335
+
336
+        if (empty($newPasswords)) {
337
+            $this->output->writeln("\nAll users already had a key-pair, no further action needed.\n");
338
+            return;
339
+        }
340
+
341
+        $table->setRows($newPasswords);
342
+        $table->render();
343
+
344
+        if (!empty($unchangedPasswords)) {
345
+            $this->output->writeln("\nThe following users already had a key-pair which was reused without setting a new password:\n");
346
+            foreach ($unchangedPasswords as $uid) {
347
+                $this->output->writeln("    $uid");
348
+            }
349
+        }
350
+
351
+        $this->writePasswordsToFile($newPasswords);
352
+
353
+        $this->output->writeln('');
354
+        $question = new ConfirmationQuestion('Do you want to send the passwords directly to the users by mail? (y/n) ', false);
355
+        if ($this->questionHelper->ask($this->input, $this->output, $question)) {
356
+            $this->sendPasswordsByMail();
357
+        }
358
+    }
359
+
360
+    /**
361
+     * write one-time encryption passwords to a csv file
362
+     *
363
+     * @param array $passwords
364
+     */
365
+    protected function writePasswordsToFile(array $passwords) {
366
+        $fp = $this->rootView->fopen('oneTimeEncryptionPasswords.csv', 'w');
367
+        foreach ($passwords as $pwd) {
368
+            fputcsv($fp, $pwd);
369
+        }
370
+        fclose($fp);
371
+        $this->output->writeln("\n");
372
+        $this->output->writeln('A list of all newly created passwords was written to data/oneTimeEncryptionPasswords.csv');
373
+        $this->output->writeln('');
374
+        $this->output->writeln('Each of these users need to login to the web interface, go to the');
375
+        $this->output->writeln('personal settings section "basic encryption module" and');
376
+        $this->output->writeln('update the private key password to match the login password again by');
377
+        $this->output->writeln('entering the one-time password into the "old log-in password" field');
378
+        $this->output->writeln('and their current login password');
379
+    }
380
+
381
+    /**
382
+     * setup user file system
383
+     *
384
+     * @param string $uid
385
+     */
386
+    protected function setupUserFS($uid) {
387
+        \OC_Util::tearDownFS();
388
+        \OC_Util::setupFS($uid);
389
+    }
390
+
391
+    /**
392
+     * generate one time password for the user and store it in a array
393
+     *
394
+     * @param string $uid
395
+     * @return string password
396
+     */
397
+    protected function generateOneTimePassword($uid) {
398
+        $password = $this->secureRandom->generate(8);
399
+        $this->userPasswords[$uid] = $password;
400
+        return $password;
401
+    }
402
+
403
+    /**
404
+     * send encryption key passwords to the users by mail
405
+     */
406
+    protected function sendPasswordsByMail() {
407
+        $noMail = [];
408
+
409
+        $this->output->writeln('');
410
+        $progress = new ProgressBar($this->output, count($this->userPasswords));
411
+        $progress->start();
412
+
413
+        foreach ($this->userPasswords as $uid => $password) {
414
+            $progress->advance();
415
+            if (!empty($password)) {
416
+                $recipient = $this->userManager->get($uid);
417
+                $recipientDisplayName = $recipient->getDisplayName();
418
+                $to = $recipient->getEMailAddress();
419
+
420
+                if ($to === '' || $to === null) {
421
+                    $noMail[] = $uid;
422
+                    continue;
423
+                }
424
+
425
+                $subject = $this->l->t('one-time password for server-side-encryption');
426
+                [$htmlBody, $textBody] = $this->createMailBody($password);
427
+
428
+                // send it out now
429
+                try {
430
+                    $message = $this->mailer->createMessage();
431
+                    $message->setSubject($subject);
432
+                    $message->setTo([$to => $recipientDisplayName]);
433
+                    $message->setHtmlBody($htmlBody);
434
+                    $message->setPlainBody($textBody);
435
+                    $message->setFrom([
436
+                        \OCP\Util::getDefaultEmailAddress('admin-noreply')
437
+                    ]);
438
+
439
+                    $this->mailer->send($message);
440
+                } catch (\Exception $e) {
441
+                    $noMail[] = $uid;
442
+                }
443
+            }
444
+        }
445
+
446
+        $progress->finish();
447
+
448
+        if (empty($noMail)) {
449
+            $this->output->writeln("\n\nPassword successfully send to all users");
450
+        } else {
451
+            $table = new Table($this->output);
452
+            $table->setHeaders(['Username', 'Private key password']);
453
+            $this->output->writeln("\n\nCould not send password to following users:\n");
454
+            $rows = [];
455
+            foreach ($noMail as $uid) {
456
+                $rows[] = [$uid, $this->userPasswords[$uid]];
457
+            }
458
+            $table->setRows($rows);
459
+            $table->render();
460
+        }
461
+    }
462
+
463
+    /**
464
+     * create mail body for plain text and html mail
465
+     *
466
+     * @param string $password one-time encryption password
467
+     * @return array an array of the html mail body and the plain text mail body
468
+     */
469
+    protected function createMailBody($password) {
470
+        $html = new \OC_Template("encryption", "mail", "");
471
+        $html->assign('password', $password);
472
+        $htmlMail = $html->fetchPage();
473
+
474
+        $plainText = new \OC_Template("encryption", "altmail", "");
475
+        $plainText->assign('password', $password);
476
+        $plainTextMail = $plainText->fetchPage();
477
+
478
+        return [$htmlMail, $plainTextMail];
479
+    }
480 480
 }
Please login to merge, or discard this patch.
apps/files/lib/Command/Scan.php 2 patches
Indentation   +273 added lines, -273 removed lines patch added patch discarded remove patch
@@ -53,277 +53,277 @@
 block discarded – undo
53 53
 
54 54
 class Scan extends Base {
55 55
 
56
-	/** @var IUserManager $userManager */
57
-	private $userManager;
58
-	/** @var float */
59
-	protected $execTime = 0;
60
-	/** @var int */
61
-	protected $foldersCounter = 0;
62
-	/** @var int */
63
-	protected $filesCounter = 0;
64
-
65
-	public function __construct(IUserManager $userManager) {
66
-		$this->userManager = $userManager;
67
-		parent::__construct();
68
-	}
69
-
70
-	protected function configure() {
71
-		parent::configure();
72
-
73
-		$this
74
-			->setName('files:scan')
75
-			->setDescription('rescan filesystem')
76
-			->addArgument(
77
-				'user_id',
78
-				InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
79
-				'will rescan all files of the given user(s)'
80
-			)
81
-			->addOption(
82
-				'path',
83
-				'p',
84
-				InputArgument::OPTIONAL,
85
-				'limit rescan to this path, eg. --path="/alice/files/Music", the user_id is determined by the path and the user_id parameter and --all are ignored'
86
-			)
87
-			->addOption(
88
-				'all',
89
-				null,
90
-				InputOption::VALUE_NONE,
91
-				'will rescan all files of all known users'
92
-			)->addOption(
93
-				'unscanned',
94
-				null,
95
-				InputOption::VALUE_NONE,
96
-				'only scan files which are marked as not fully scanned'
97
-			)->addOption(
98
-				'shallow',
99
-				null,
100
-				InputOption::VALUE_NONE,
101
-				'do not scan folders recursively'
102
-			)->addOption(
103
-				'home-only',
104
-				null,
105
-				InputOption::VALUE_NONE,
106
-				'only scan the home storage, ignoring any mounted external storage or share'
107
-			);
108
-	}
109
-
110
-	public function checkScanWarning($fullPath, OutputInterface $output) {
111
-		$normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
112
-		$path = basename($fullPath);
113
-
114
-		if ($normalizedPath !== $path) {
115
-			$output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
116
-		}
117
-	}
118
-
119
-	protected function scanFiles($user, $path, OutputInterface $output, $backgroundScan = false, $recursive = true, $homeOnly = false) {
120
-		$connection = $this->reconnectToDatabase($output);
121
-		$scanner = new \OC\Files\Utils\Scanner(
122
-			$user,
123
-			new ConnectionAdapter($connection),
124
-			\OC::$server->query(IEventDispatcher::class),
125
-			\OC::$server->getLogger()
126
-		);
127
-
128
-		# check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
129
-
130
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
131
-			$output->writeln("\tFile\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
132
-			++$this->filesCounter;
133
-			$this->abortIfInterrupted();
134
-		});
135
-
136
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
137
-			$output->writeln("\tFolder\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
138
-			++$this->foldersCounter;
139
-			$this->abortIfInterrupted();
140
-		});
141
-
142
-		$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
143
-			$output->writeln('Error while scanning, storage not available (' . $e->getMessage() . ')', OutputInterface::VERBOSITY_VERBOSE);
144
-		});
145
-
146
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
147
-			$this->checkScanWarning($path, $output);
148
-		});
149
-
150
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
151
-			$this->checkScanWarning($path, $output);
152
-		});
153
-
154
-		try {
155
-			if ($backgroundScan) {
156
-				$scanner->backgroundScan($path);
157
-			} else {
158
-				$scanner->scan($path, $recursive, $homeOnly ? [$this, 'filterHomeMount'] : null);
159
-			}
160
-		} catch (ForbiddenException $e) {
161
-			$output->writeln("<error>Home storage for user $user not writable</error>");
162
-			$output->writeln('Make sure you\'re running the scan command only as the user the web server runs as');
163
-		} catch (InterruptedException $e) {
164
-			# exit the function if ctrl-c has been pressed
165
-			$output->writeln('Interrupted by user');
166
-		} catch (NotFoundException $e) {
167
-			$output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
168
-		} catch (\Exception $e) {
169
-			$output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
170
-			$output->writeln('<error>' . $e->getTraceAsString() . '</error>');
171
-		}
172
-	}
173
-
174
-	public function filterHomeMount(IMountPoint $mountPoint) {
175
-		// any mountpoint inside '/$user/files/'
176
-		return substr_count($mountPoint->getMountPoint(), '/') <= 3;
177
-	}
178
-
179
-	protected function execute(InputInterface $input, OutputInterface $output): int {
180
-		$inputPath = $input->getOption('path');
181
-		if ($inputPath) {
182
-			$inputPath = '/' . trim($inputPath, '/');
183
-			[, $user,] = explode('/', $inputPath, 3);
184
-			$users = [$user];
185
-		} elseif ($input->getOption('all')) {
186
-			$users = $this->userManager->search('');
187
-		} else {
188
-			$users = $input->getArgument('user_id');
189
-		}
190
-
191
-		# restrict the verbosity level to VERBOSITY_VERBOSE
192
-		if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
193
-			$output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
194
-		}
195
-
196
-		# check quantity of users to be process and show it on the command line
197
-		$users_total = count($users);
198
-		if ($users_total === 0) {
199
-			$output->writeln('<error>Please specify the user id to scan, --all to scan for all users or --path=...</error>');
200
-			return 1;
201
-		}
202
-
203
-		$this->initTools();
204
-
205
-		$user_count = 0;
206
-		foreach ($users as $user) {
207
-			if (is_object($user)) {
208
-				$user = $user->getUID();
209
-			}
210
-			$path = $inputPath ? $inputPath : '/' . $user;
211
-			++$user_count;
212
-			if ($this->userManager->userExists($user)) {
213
-				$output->writeln("Starting scan for user $user_count out of $users_total ($user)");
214
-				$this->scanFiles($user, $path, $output, $input->getOption('unscanned'), !$input->getOption('shallow'), $input->getOption('home-only'));
215
-				$output->writeln('', OutputInterface::VERBOSITY_VERBOSE);
216
-			} else {
217
-				$output->writeln("<error>Unknown user $user_count $user</error>");
218
-				$output->writeln('', OutputInterface::VERBOSITY_VERBOSE);
219
-			}
220
-
221
-			try {
222
-				$this->abortIfInterrupted();
223
-			} catch (InterruptedException $e) {
224
-				break;
225
-			}
226
-		}
227
-
228
-		$this->presentStats($output);
229
-		return 0;
230
-	}
231
-
232
-	/**
233
-	 * Initialises some useful tools for the Command
234
-	 */
235
-	protected function initTools() {
236
-		// Start the timer
237
-		$this->execTime = -microtime(true);
238
-		// Convert PHP errors to exceptions
239
-		set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
240
-	}
241
-
242
-	/**
243
-	 * Processes PHP errors as exceptions in order to be able to keep track of problems
244
-	 *
245
-	 * @see https://www.php.net/manual/en/function.set-error-handler.php
246
-	 *
247
-	 * @param int $severity the level of the error raised
248
-	 * @param string $message
249
-	 * @param string $file the filename that the error was raised in
250
-	 * @param int $line the line number the error was raised
251
-	 *
252
-	 * @throws \ErrorException
253
-	 */
254
-	public function exceptionErrorHandler($severity, $message, $file, $line) {
255
-		if (!(error_reporting() & $severity)) {
256
-			// This error code is not included in error_reporting
257
-			return;
258
-		}
259
-		throw new \ErrorException($message, 0, $severity, $file, $line);
260
-	}
261
-
262
-	/**
263
-	 * @param OutputInterface $output
264
-	 */
265
-	protected function presentStats(OutputInterface $output) {
266
-		// Stop the timer
267
-		$this->execTime += microtime(true);
268
-
269
-		$headers = [
270
-			'Folders', 'Files', 'Elapsed time'
271
-		];
272
-
273
-		$this->showSummary($headers, null, $output);
274
-	}
275
-
276
-	/**
277
-	 * Shows a summary of operations
278
-	 *
279
-	 * @param string[] $headers
280
-	 * @param string[] $rows
281
-	 * @param OutputInterface $output
282
-	 */
283
-	protected function showSummary($headers, $rows, OutputInterface $output) {
284
-		$niceDate = $this->formatExecTime();
285
-		if (!$rows) {
286
-			$rows = [
287
-				$this->foldersCounter,
288
-				$this->filesCounter,
289
-				$niceDate,
290
-			];
291
-		}
292
-		$table = new Table($output);
293
-		$table
294
-			->setHeaders($headers)
295
-			->setRows([$rows]);
296
-		$table->render();
297
-	}
298
-
299
-
300
-	/**
301
-	 * Formats microtime into a human readable format
302
-	 *
303
-	 * @return string
304
-	 */
305
-	protected function formatExecTime() {
306
-		$secs = round($this->execTime);
307
-		# convert seconds into HH:MM:SS form
308
-		return sprintf('%02d:%02d:%02d', ($secs / 3600), ($secs / 60 % 60), $secs % 60);
309
-	}
310
-
311
-	protected function reconnectToDatabase(OutputInterface $output): Connection {
312
-		/** @var Connection $connection */
313
-		$connection = \OC::$server->get(Connection::class);
314
-		try {
315
-			$connection->close();
316
-		} catch (\Exception $ex) {
317
-			$output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
318
-		}
319
-		while (!$connection->isConnected()) {
320
-			try {
321
-				$connection->connect();
322
-			} catch (\Exception $ex) {
323
-				$output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
324
-				sleep(60);
325
-			}
326
-		}
327
-		return $connection;
328
-	}
56
+    /** @var IUserManager $userManager */
57
+    private $userManager;
58
+    /** @var float */
59
+    protected $execTime = 0;
60
+    /** @var int */
61
+    protected $foldersCounter = 0;
62
+    /** @var int */
63
+    protected $filesCounter = 0;
64
+
65
+    public function __construct(IUserManager $userManager) {
66
+        $this->userManager = $userManager;
67
+        parent::__construct();
68
+    }
69
+
70
+    protected function configure() {
71
+        parent::configure();
72
+
73
+        $this
74
+            ->setName('files:scan')
75
+            ->setDescription('rescan filesystem')
76
+            ->addArgument(
77
+                'user_id',
78
+                InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
79
+                'will rescan all files of the given user(s)'
80
+            )
81
+            ->addOption(
82
+                'path',
83
+                'p',
84
+                InputArgument::OPTIONAL,
85
+                'limit rescan to this path, eg. --path="/alice/files/Music", the user_id is determined by the path and the user_id parameter and --all are ignored'
86
+            )
87
+            ->addOption(
88
+                'all',
89
+                null,
90
+                InputOption::VALUE_NONE,
91
+                'will rescan all files of all known users'
92
+            )->addOption(
93
+                'unscanned',
94
+                null,
95
+                InputOption::VALUE_NONE,
96
+                'only scan files which are marked as not fully scanned'
97
+            )->addOption(
98
+                'shallow',
99
+                null,
100
+                InputOption::VALUE_NONE,
101
+                'do not scan folders recursively'
102
+            )->addOption(
103
+                'home-only',
104
+                null,
105
+                InputOption::VALUE_NONE,
106
+                'only scan the home storage, ignoring any mounted external storage or share'
107
+            );
108
+    }
109
+
110
+    public function checkScanWarning($fullPath, OutputInterface $output) {
111
+        $normalizedPath = basename(\OC\Files\Filesystem::normalizePath($fullPath));
112
+        $path = basename($fullPath);
113
+
114
+        if ($normalizedPath !== $path) {
115
+            $output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
116
+        }
117
+    }
118
+
119
+    protected function scanFiles($user, $path, OutputInterface $output, $backgroundScan = false, $recursive = true, $homeOnly = false) {
120
+        $connection = $this->reconnectToDatabase($output);
121
+        $scanner = new \OC\Files\Utils\Scanner(
122
+            $user,
123
+            new ConnectionAdapter($connection),
124
+            \OC::$server->query(IEventDispatcher::class),
125
+            \OC::$server->getLogger()
126
+        );
127
+
128
+        # check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
129
+
130
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
131
+            $output->writeln("\tFile\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
132
+            ++$this->filesCounter;
133
+            $this->abortIfInterrupted();
134
+        });
135
+
136
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
137
+            $output->writeln("\tFolder\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
138
+            ++$this->foldersCounter;
139
+            $this->abortIfInterrupted();
140
+        });
141
+
142
+        $scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
143
+            $output->writeln('Error while scanning, storage not available (' . $e->getMessage() . ')', OutputInterface::VERBOSITY_VERBOSE);
144
+        });
145
+
146
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
147
+            $this->checkScanWarning($path, $output);
148
+        });
149
+
150
+        $scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
151
+            $this->checkScanWarning($path, $output);
152
+        });
153
+
154
+        try {
155
+            if ($backgroundScan) {
156
+                $scanner->backgroundScan($path);
157
+            } else {
158
+                $scanner->scan($path, $recursive, $homeOnly ? [$this, 'filterHomeMount'] : null);
159
+            }
160
+        } catch (ForbiddenException $e) {
161
+            $output->writeln("<error>Home storage for user $user not writable</error>");
162
+            $output->writeln('Make sure you\'re running the scan command only as the user the web server runs as');
163
+        } catch (InterruptedException $e) {
164
+            # exit the function if ctrl-c has been pressed
165
+            $output->writeln('Interrupted by user');
166
+        } catch (NotFoundException $e) {
167
+            $output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
168
+        } catch (\Exception $e) {
169
+            $output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
170
+            $output->writeln('<error>' . $e->getTraceAsString() . '</error>');
171
+        }
172
+    }
173
+
174
+    public function filterHomeMount(IMountPoint $mountPoint) {
175
+        // any mountpoint inside '/$user/files/'
176
+        return substr_count($mountPoint->getMountPoint(), '/') <= 3;
177
+    }
178
+
179
+    protected function execute(InputInterface $input, OutputInterface $output): int {
180
+        $inputPath = $input->getOption('path');
181
+        if ($inputPath) {
182
+            $inputPath = '/' . trim($inputPath, '/');
183
+            [, $user,] = explode('/', $inputPath, 3);
184
+            $users = [$user];
185
+        } elseif ($input->getOption('all')) {
186
+            $users = $this->userManager->search('');
187
+        } else {
188
+            $users = $input->getArgument('user_id');
189
+        }
190
+
191
+        # restrict the verbosity level to VERBOSITY_VERBOSE
192
+        if ($output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
193
+            $output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
194
+        }
195
+
196
+        # check quantity of users to be process and show it on the command line
197
+        $users_total = count($users);
198
+        if ($users_total === 0) {
199
+            $output->writeln('<error>Please specify the user id to scan, --all to scan for all users or --path=...</error>');
200
+            return 1;
201
+        }
202
+
203
+        $this->initTools();
204
+
205
+        $user_count = 0;
206
+        foreach ($users as $user) {
207
+            if (is_object($user)) {
208
+                $user = $user->getUID();
209
+            }
210
+            $path = $inputPath ? $inputPath : '/' . $user;
211
+            ++$user_count;
212
+            if ($this->userManager->userExists($user)) {
213
+                $output->writeln("Starting scan for user $user_count out of $users_total ($user)");
214
+                $this->scanFiles($user, $path, $output, $input->getOption('unscanned'), !$input->getOption('shallow'), $input->getOption('home-only'));
215
+                $output->writeln('', OutputInterface::VERBOSITY_VERBOSE);
216
+            } else {
217
+                $output->writeln("<error>Unknown user $user_count $user</error>");
218
+                $output->writeln('', OutputInterface::VERBOSITY_VERBOSE);
219
+            }
220
+
221
+            try {
222
+                $this->abortIfInterrupted();
223
+            } catch (InterruptedException $e) {
224
+                break;
225
+            }
226
+        }
227
+
228
+        $this->presentStats($output);
229
+        return 0;
230
+    }
231
+
232
+    /**
233
+     * Initialises some useful tools for the Command
234
+     */
235
+    protected function initTools() {
236
+        // Start the timer
237
+        $this->execTime = -microtime(true);
238
+        // Convert PHP errors to exceptions
239
+        set_error_handler([$this, 'exceptionErrorHandler'], E_ALL);
240
+    }
241
+
242
+    /**
243
+     * Processes PHP errors as exceptions in order to be able to keep track of problems
244
+     *
245
+     * @see https://www.php.net/manual/en/function.set-error-handler.php
246
+     *
247
+     * @param int $severity the level of the error raised
248
+     * @param string $message
249
+     * @param string $file the filename that the error was raised in
250
+     * @param int $line the line number the error was raised
251
+     *
252
+     * @throws \ErrorException
253
+     */
254
+    public function exceptionErrorHandler($severity, $message, $file, $line) {
255
+        if (!(error_reporting() & $severity)) {
256
+            // This error code is not included in error_reporting
257
+            return;
258
+        }
259
+        throw new \ErrorException($message, 0, $severity, $file, $line);
260
+    }
261
+
262
+    /**
263
+     * @param OutputInterface $output
264
+     */
265
+    protected function presentStats(OutputInterface $output) {
266
+        // Stop the timer
267
+        $this->execTime += microtime(true);
268
+
269
+        $headers = [
270
+            'Folders', 'Files', 'Elapsed time'
271
+        ];
272
+
273
+        $this->showSummary($headers, null, $output);
274
+    }
275
+
276
+    /**
277
+     * Shows a summary of operations
278
+     *
279
+     * @param string[] $headers
280
+     * @param string[] $rows
281
+     * @param OutputInterface $output
282
+     */
283
+    protected function showSummary($headers, $rows, OutputInterface $output) {
284
+        $niceDate = $this->formatExecTime();
285
+        if (!$rows) {
286
+            $rows = [
287
+                $this->foldersCounter,
288
+                $this->filesCounter,
289
+                $niceDate,
290
+            ];
291
+        }
292
+        $table = new Table($output);
293
+        $table
294
+            ->setHeaders($headers)
295
+            ->setRows([$rows]);
296
+        $table->render();
297
+    }
298
+
299
+
300
+    /**
301
+     * Formats microtime into a human readable format
302
+     *
303
+     * @return string
304
+     */
305
+    protected function formatExecTime() {
306
+        $secs = round($this->execTime);
307
+        # convert seconds into HH:MM:SS form
308
+        return sprintf('%02d:%02d:%02d', ($secs / 3600), ($secs / 60 % 60), $secs % 60);
309
+    }
310
+
311
+    protected function reconnectToDatabase(OutputInterface $output): Connection {
312
+        /** @var Connection $connection */
313
+        $connection = \OC::$server->get(Connection::class);
314
+        try {
315
+            $connection->close();
316
+        } catch (\Exception $ex) {
317
+            $output->writeln("<info>Error while disconnecting from database: {$ex->getMessage()}</info>");
318
+        }
319
+        while (!$connection->isConnected()) {
320
+            try {
321
+                $connection->connect();
322
+            } catch (\Exception $ex) {
323
+                $output->writeln("<info>Error while re-connecting to database: {$ex->getMessage()}</info>");
324
+                sleep(60);
325
+            }
326
+        }
327
+        return $connection;
328
+    }
329 329
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -112,7 +112,7 @@  discard block
 block discarded – undo
112 112
 		$path = basename($fullPath);
113 113
 
114 114
 		if ($normalizedPath !== $path) {
115
-			$output->writeln("\t<error>Entry \"" . $fullPath . '" will not be accessible due to incompatible encoding</error>');
115
+			$output->writeln("\t<error>Entry \"".$fullPath.'" will not be accessible due to incompatible encoding</error>');
116 116
 		}
117 117
 	}
118 118
 
@@ -127,27 +127,27 @@  discard block
 block discarded – undo
127 127
 
128 128
 		# check on each file/folder if there was a user interrupt (ctrl-c) and throw an exception
129 129
 
130
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
130
+		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) {
131 131
 			$output->writeln("\tFile\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
132 132
 			++$this->filesCounter;
133 133
 			$this->abortIfInterrupted();
134 134
 		});
135 135
 
136
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
136
+		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) {
137 137
 			$output->writeln("\tFolder\t<info>$path</info>", OutputInterface::VERBOSITY_VERBOSE);
138 138
 			++$this->foldersCounter;
139 139
 			$this->abortIfInterrupted();
140 140
 		});
141 141
 
142
-		$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function (StorageNotAvailableException $e) use ($output) {
143
-			$output->writeln('Error while scanning, storage not available (' . $e->getMessage() . ')', OutputInterface::VERBOSITY_VERBOSE);
142
+		$scanner->listen('\OC\Files\Utils\Scanner', 'StorageNotAvailable', function(StorageNotAvailableException $e) use ($output) {
143
+			$output->writeln('Error while scanning, storage not available ('.$e->getMessage().')', OutputInterface::VERBOSITY_VERBOSE);
144 144
 		});
145 145
 
146
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function ($path) use ($output) {
146
+		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFile', function($path) use ($output) {
147 147
 			$this->checkScanWarning($path, $output);
148 148
 		});
149 149
 
150
-		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function ($path) use ($output) {
150
+		$scanner->listen('\OC\Files\Utils\Scanner', 'scanFolder', function($path) use ($output) {
151 151
 			$this->checkScanWarning($path, $output);
152 152
 		});
153 153
 
@@ -164,10 +164,10 @@  discard block
 block discarded – undo
164 164
 			# exit the function if ctrl-c has been pressed
165 165
 			$output->writeln('Interrupted by user');
166 166
 		} catch (NotFoundException $e) {
167
-			$output->writeln('<error>Path not found: ' . $e->getMessage() . '</error>');
167
+			$output->writeln('<error>Path not found: '.$e->getMessage().'</error>');
168 168
 		} catch (\Exception $e) {
169
-			$output->writeln('<error>Exception during scan: ' . $e->getMessage() . '</error>');
170
-			$output->writeln('<error>' . $e->getTraceAsString() . '</error>');
169
+			$output->writeln('<error>Exception during scan: '.$e->getMessage().'</error>');
170
+			$output->writeln('<error>'.$e->getTraceAsString().'</error>');
171 171
 		}
172 172
 	}
173 173
 
@@ -179,8 +179,8 @@  discard block
 block discarded – undo
179 179
 	protected function execute(InputInterface $input, OutputInterface $output): int {
180 180
 		$inputPath = $input->getOption('path');
181 181
 		if ($inputPath) {
182
-			$inputPath = '/' . trim($inputPath, '/');
183
-			[, $user,] = explode('/', $inputPath, 3);
182
+			$inputPath = '/'.trim($inputPath, '/');
183
+			[, $user, ] = explode('/', $inputPath, 3);
184 184
 			$users = [$user];
185 185
 		} elseif ($input->getOption('all')) {
186 186
 			$users = $this->userManager->search('');
@@ -207,7 +207,7 @@  discard block
 block discarded – undo
207 207
 			if (is_object($user)) {
208 208
 				$user = $user->getUID();
209 209
 			}
210
-			$path = $inputPath ? $inputPath : '/' . $user;
210
+			$path = $inputPath ? $inputPath : '/'.$user;
211 211
 			++$user_count;
212 212
 			if ($this->userManager->userExists($user)) {
213 213
 				$output->writeln("Starting scan for user $user_count out of $users_total ($user)");
Please login to merge, or discard this patch.
apps/files/lib/Activity/Provider.php 1 patch
Indentation   +504 added lines, -504 removed lines patch added patch discarded remove patch
@@ -44,508 +44,508 @@
 block discarded – undo
44 44
 
45 45
 class Provider implements IProvider {
46 46
 
47
-	/** @var IFactory */
48
-	protected $languageFactory;
49
-
50
-	/** @var IL10N */
51
-	protected $l;
52
-	/** @var IL10N */
53
-	protected $activityLang;
54
-
55
-	/** @var IURLGenerator */
56
-	protected $url;
57
-
58
-	/** @var IManager */
59
-	protected $activityManager;
60
-
61
-	/** @var IUserManager */
62
-	protected $userManager;
63
-
64
-	/** @var IRootFolder */
65
-	protected $rootFolder;
66
-
67
-	/** @var IEventMerger */
68
-	protected $eventMerger;
69
-
70
-	/** @var ICloudIdManager */
71
-	protected $cloudIdManager;
72
-
73
-	/** @var IContactsManager */
74
-	protected $contactsManager;
75
-
76
-	/** @var string[] cached displayNames - key is the cloud id and value the displayname */
77
-	protected $displayNames = [];
78
-
79
-	protected $fileIsEncrypted = false;
80
-
81
-	public function __construct(IFactory $languageFactory,
82
-								IURLGenerator $url,
83
-								IManager $activityManager,
84
-								IUserManager $userManager,
85
-								IRootFolder $rootFolder,
86
-								ICloudIdManager $cloudIdManager,
87
-								IContactsManager $contactsManager,
88
-								IEventMerger $eventMerger) {
89
-		$this->languageFactory = $languageFactory;
90
-		$this->url = $url;
91
-		$this->activityManager = $activityManager;
92
-		$this->userManager = $userManager;
93
-		$this->rootFolder = $rootFolder;
94
-		$this->cloudIdManager = $cloudIdManager;
95
-		$this->contactsManager = $contactsManager;
96
-		$this->eventMerger = $eventMerger;
97
-	}
98
-
99
-	/**
100
-	 * @param string $language
101
-	 * @param IEvent $event
102
-	 * @param IEvent|null $previousEvent
103
-	 * @return IEvent
104
-	 * @throws \InvalidArgumentException
105
-	 * @since 11.0.0
106
-	 */
107
-	public function parse($language, IEvent $event, IEvent $previousEvent = null) {
108
-		if ($event->getApp() !== 'files') {
109
-			throw new \InvalidArgumentException();
110
-		}
111
-
112
-		$this->l = $this->languageFactory->get('files', $language);
113
-		$this->activityLang = $this->languageFactory->get('activity', $language);
114
-
115
-		if ($this->activityManager->isFormattingFilteredObject()) {
116
-			try {
117
-				return $this->parseShortVersion($event, $previousEvent);
118
-			} catch (\InvalidArgumentException $e) {
119
-				// Ignore and simply use the long version...
120
-			}
121
-		}
122
-
123
-		return $this->parseLongVersion($event, $previousEvent);
124
-	}
125
-
126
-	protected function setIcon(IEvent $event, string $icon, string $app = 'files') {
127
-		if ($this->activityManager->getRequirePNG()) {
128
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath($app, $icon . '.png')));
129
-		} else {
130
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath($app, $icon . '.svg')));
131
-		}
132
-	}
133
-
134
-	/**
135
-	 * @param IEvent $event
136
-	 * @param IEvent|null $previousEvent
137
-	 * @return IEvent
138
-	 * @throws \InvalidArgumentException
139
-	 * @since 11.0.0
140
-	 */
141
-	public function parseShortVersion(IEvent $event, IEvent $previousEvent = null) {
142
-		$parsedParameters = $this->getParameters($event);
143
-
144
-		if ($event->getSubject() === 'created_by') {
145
-			$subject = $this->l->t('Created by {user}');
146
-			$this->setIcon($event, 'add-color');
147
-		} elseif ($event->getSubject() === 'changed_by') {
148
-			$subject = $this->l->t('Changed by {user}');
149
-			$this->setIcon($event, 'change');
150
-		} elseif ($event->getSubject() === 'deleted_by') {
151
-			$subject = $this->l->t('Deleted by {user}');
152
-			$this->setIcon($event, 'delete-color');
153
-		} elseif ($event->getSubject() === 'restored_by') {
154
-			$subject = $this->l->t('Restored by {user}');
155
-			$this->setIcon($event, 'actions/history', 'core');
156
-		} elseif ($event->getSubject() === 'renamed_by') {
157
-			$subject = $this->l->t('Renamed by {user}');
158
-			$this->setIcon($event, 'change');
159
-		} elseif ($event->getSubject() === 'moved_by') {
160
-			$subject = $this->l->t('Moved by {user}');
161
-			$this->setIcon($event, 'change');
162
-		} else {
163
-			throw new \InvalidArgumentException();
164
-		}
165
-
166
-		if (!isset($parsedParameters['user'])) {
167
-			// External user via public link share
168
-			$subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
169
-		}
170
-
171
-		$this->setSubjects($event, $subject, $parsedParameters);
172
-
173
-		return $this->eventMerger->mergeEvents('user', $event, $previousEvent);
174
-	}
175
-
176
-	/**
177
-	 * @param IEvent $event
178
-	 * @param IEvent|null $previousEvent
179
-	 * @return IEvent
180
-	 * @throws \InvalidArgumentException
181
-	 * @since 11.0.0
182
-	 */
183
-	public function parseLongVersion(IEvent $event, IEvent $previousEvent = null) {
184
-		$this->fileIsEncrypted = false;
185
-		$parsedParameters = $this->getParameters($event);
186
-
187
-		if ($event->getSubject() === 'created_self') {
188
-			$subject = $this->l->t('You created {file}');
189
-			if ($this->fileIsEncrypted) {
190
-				$subject = $this->l->t('You created an encrypted file in {file}');
191
-			}
192
-			$this->setIcon($event, 'add-color');
193
-		} elseif ($event->getSubject() === 'created_by') {
194
-			$subject = $this->l->t('{user} created {file}');
195
-			if ($this->fileIsEncrypted) {
196
-				$subject = $this->l->t('{user} created an encrypted file in {file}');
197
-			}
198
-			$this->setIcon($event, 'add-color');
199
-		} elseif ($event->getSubject() === 'created_public') {
200
-			$subject = $this->l->t('{file} was created in a public folder');
201
-			$this->setIcon($event, 'add-color');
202
-		} elseif ($event->getSubject() === 'changed_self') {
203
-			$subject = $this->l->t('You changed {file}');
204
-			if ($this->fileIsEncrypted) {
205
-				$subject = $this->l->t('You changed an encrypted file in {file}');
206
-			}
207
-			$this->setIcon($event, 'change');
208
-		} elseif ($event->getSubject() === 'changed_by') {
209
-			$subject = $this->l->t('{user} changed {file}');
210
-			if ($this->fileIsEncrypted) {
211
-				$subject = $this->l->t('{user} changed an encrypted file in {file}');
212
-			}
213
-			$this->setIcon($event, 'change');
214
-		} elseif ($event->getSubject() === 'deleted_self') {
215
-			$subject = $this->l->t('You deleted {file}');
216
-			if ($this->fileIsEncrypted) {
217
-				$subject = $this->l->t('You deleted an encrypted file in {file}');
218
-			}
219
-			$this->setIcon($event, 'delete-color');
220
-		} elseif ($event->getSubject() === 'deleted_by') {
221
-			$subject = $this->l->t('{user} deleted {file}');
222
-			if ($this->fileIsEncrypted) {
223
-				$subject = $this->l->t('{user} deleted an encrypted file in {file}');
224
-			}
225
-			$this->setIcon($event, 'delete-color');
226
-		} elseif ($event->getSubject() === 'restored_self') {
227
-			$subject = $this->l->t('You restored {file}');
228
-			$this->setIcon($event, 'actions/history', 'core');
229
-		} elseif ($event->getSubject() === 'restored_by') {
230
-			$subject = $this->l->t('{user} restored {file}');
231
-			$this->setIcon($event, 'actions/history', 'core');
232
-		} elseif ($event->getSubject() === 'renamed_self') {
233
-			$subject = $this->l->t('You renamed {oldfile} to {newfile}');
234
-			$this->setIcon($event, 'change');
235
-		} elseif ($event->getSubject() === 'renamed_by') {
236
-			$subject = $this->l->t('{user} renamed {oldfile} to {newfile}');
237
-			$this->setIcon($event, 'change');
238
-		} elseif ($event->getSubject() === 'moved_self') {
239
-			$subject = $this->l->t('You moved {oldfile} to {newfile}');
240
-			$this->setIcon($event, 'change');
241
-		} elseif ($event->getSubject() === 'moved_by') {
242
-			$subject = $this->l->t('{user} moved {oldfile} to {newfile}');
243
-			$this->setIcon($event, 'change');
244
-		} else {
245
-			throw new \InvalidArgumentException();
246
-		}
247
-
248
-		if ($this->fileIsEncrypted) {
249
-			$event->setSubject($event->getSubject() . '_enc', $event->getSubjectParameters());
250
-		}
251
-
252
-		if (!isset($parsedParameters['user'])) {
253
-			// External user via public link share
254
-			$subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
255
-		}
256
-
257
-		$this->setSubjects($event, $subject, $parsedParameters);
258
-
259
-		if ($event->getSubject() === 'moved_self' || $event->getSubject() === 'moved_by') {
260
-			$event = $this->eventMerger->mergeEvents('oldfile', $event, $previousEvent);
261
-		} else {
262
-			$event = $this->eventMerger->mergeEvents('file', $event, $previousEvent);
263
-		}
264
-
265
-		if ($event->getChildEvent() === null) {
266
-			// Couldn't group by file, maybe we can group by user
267
-			$event = $this->eventMerger->mergeEvents('user', $event, $previousEvent);
268
-		}
269
-
270
-		return $event;
271
-	}
272
-
273
-	protected function setSubjects(IEvent $event, $subject, array $parameters) {
274
-		$placeholders = $replacements = [];
275
-		foreach ($parameters as $placeholder => $parameter) {
276
-			$placeholders[] = '{' . $placeholder . '}';
277
-			if ($parameter['type'] === 'file') {
278
-				$replacements[] = $parameter['path'];
279
-			} else {
280
-				$replacements[] = $parameter['name'];
281
-			}
282
-		}
283
-
284
-		$event->setParsedSubject(str_replace($placeholders, $replacements, $subject))
285
-			->setRichSubject($subject, $parameters);
286
-	}
287
-
288
-	/**
289
-	 * @param IEvent $event
290
-	 * @return array
291
-	 * @throws \InvalidArgumentException
292
-	 */
293
-	protected function getParameters(IEvent $event) {
294
-		$parameters = $event->getSubjectParameters();
295
-		switch ($event->getSubject()) {
296
-			case 'created_self':
297
-			case 'created_public':
298
-			case 'changed_self':
299
-			case 'deleted_self':
300
-			case 'restored_self':
301
-				return [
302
-					'file' => $this->getFile($parameters[0], $event),
303
-				];
304
-			case 'created_by':
305
-			case 'changed_by':
306
-			case 'deleted_by':
307
-			case 'restored_by':
308
-				if ($parameters[1] === '') {
309
-					// External user via public link share
310
-					return [
311
-						'file' => $this->getFile($parameters[0], $event),
312
-					];
313
-				}
314
-				return [
315
-					'file' => $this->getFile($parameters[0], $event),
316
-					'user' => $this->getUser($parameters[1]),
317
-				];
318
-			case 'renamed_self':
319
-			case 'moved_self':
320
-				return [
321
-					'newfile' => $this->getFile($parameters[0]),
322
-					'oldfile' => $this->getFile($parameters[1]),
323
-				];
324
-			case 'renamed_by':
325
-			case 'moved_by':
326
-				if ($parameters[1] === '') {
327
-					// External user via public link share
328
-					return [
329
-						'newfile' => $this->getFile($parameters[0]),
330
-						'oldfile' => $this->getFile($parameters[2]),
331
-					];
332
-				}
333
-				return [
334
-					'newfile' => $this->getFile($parameters[0]),
335
-					'user' => $this->getUser($parameters[1]),
336
-					'oldfile' => $this->getFile($parameters[2]),
337
-				];
338
-		}
339
-		return [];
340
-	}
341
-
342
-	/**
343
-	 * @param array|string $parameter
344
-	 * @param IEvent|null $event
345
-	 * @return array
346
-	 * @throws \InvalidArgumentException
347
-	 */
348
-	protected function getFile($parameter, IEvent $event = null) {
349
-		if (is_array($parameter)) {
350
-			$path = reset($parameter);
351
-			$id = (string) key($parameter);
352
-		} elseif ($event !== null) {
353
-			// Legacy from before ownCloud 8.2
354
-			$path = $parameter;
355
-			$id = $event->getObjectId();
356
-		} else {
357
-			throw new \InvalidArgumentException('Could not generate file parameter');
358
-		}
359
-
360
-		$encryptionContainer = $this->getEndToEndEncryptionContainer($id, $path);
361
-		if ($encryptionContainer instanceof Folder) {
362
-			$this->fileIsEncrypted = true;
363
-			try {
364
-				$fullPath = rtrim($encryptionContainer->getPath(), '/');
365
-				// Remove /user/files/...
366
-				[,,, $path] = explode('/', $fullPath, 4);
367
-				if (!$path) {
368
-					throw new InvalidPathException('Path could not be split correctly');
369
-				}
370
-
371
-				return [
372
-					'type' => 'file',
373
-					'id' => $encryptionContainer->getId(),
374
-					'name' => $encryptionContainer->getName(),
375
-					'path' => $path,
376
-					'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $encryptionContainer->getId()]),
377
-				];
378
-			} catch (\Exception $e) {
379
-				// fall back to the normal one
380
-				$this->fileIsEncrypted = false;
381
-			}
382
-		}
383
-
384
-		return [
385
-			'type' => 'file',
386
-			'id' => $id,
387
-			'name' => basename($path),
388
-			'path' => trim($path, '/'),
389
-			'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $id]),
390
-		];
391
-	}
392
-
393
-	protected $fileEncrypted = [];
394
-
395
-	/**
396
-	 * Check if a file is end2end encrypted
397
-	 * @param int $fileId
398
-	 * @param string $path
399
-	 * @return Folder|null
400
-	 */
401
-	protected function getEndToEndEncryptionContainer($fileId, $path) {
402
-		if (isset($this->fileEncrypted[$fileId])) {
403
-			return $this->fileEncrypted[$fileId];
404
-		}
405
-
406
-		$fileName = basename($path);
407
-		if (!preg_match('/^[0-9a-fA-F]{32}$/', $fileName)) {
408
-			$this->fileEncrypted[$fileId] = false;
409
-			return $this->fileEncrypted[$fileId];
410
-		}
411
-
412
-		$userFolder = $this->rootFolder->getUserFolder($this->activityManager->getCurrentUserId());
413
-		$files = $userFolder->getById($fileId);
414
-		if (empty($files)) {
415
-			try {
416
-				// Deleted, try with parent
417
-				$file = $this->findExistingParent($userFolder, dirname($path));
418
-			} catch (NotFoundException $e) {
419
-				return null;
420
-			}
421
-
422
-			if (!$file instanceof Folder || !$file->isEncrypted()) {
423
-				return null;
424
-			}
425
-
426
-			$this->fileEncrypted[$fileId] = $file;
427
-			return $file;
428
-		}
429
-
430
-		$file = array_shift($files);
431
-
432
-		if ($file instanceof Folder && $file->isEncrypted()) {
433
-			// If the folder is encrypted, it is the Container,
434
-			// but can be the name is just fine.
435
-			$this->fileEncrypted[$fileId] = true;
436
-			return null;
437
-		}
438
-
439
-		$this->fileEncrypted[$fileId] = $this->getParentEndToEndEncryptionContainer($userFolder, $file);
440
-		return $this->fileEncrypted[$fileId];
441
-	}
442
-
443
-	/**
444
-	 * @param Folder $userFolder
445
-	 * @param string $path
446
-	 * @return Folder
447
-	 * @throws NotFoundException
448
-	 */
449
-	protected function findExistingParent(Folder $userFolder, $path) {
450
-		if ($path === '/') {
451
-			throw new NotFoundException('Reached the root');
452
-		}
453
-
454
-		try {
455
-			$folder = $userFolder->get(dirname($path));
456
-		} catch (NotFoundException $e) {
457
-			return $this->findExistingParent($userFolder, dirname($path));
458
-		}
459
-
460
-		return $folder;
461
-	}
462
-
463
-	/**
464
-	 * Check all parents until the user's root folder if one is encrypted
465
-	 *
466
-	 * @param Folder $userFolder
467
-	 * @param Node $file
468
-	 * @return Node|null
469
-	 */
470
-	protected function getParentEndToEndEncryptionContainer(Folder $userFolder, Node $file) {
471
-		try {
472
-			$parent = $file->getParent();
473
-
474
-			if ($userFolder->getId() === $parent->getId()) {
475
-				return null;
476
-			}
477
-		} catch (\Exception $e) {
478
-			return null;
479
-		}
480
-
481
-		if ($parent->isEncrypted()) {
482
-			return $parent;
483
-		}
484
-
485
-		return $this->getParentEndToEndEncryptionContainer($userFolder, $parent);
486
-	}
487
-
488
-	/**
489
-	 * @param string $uid
490
-	 * @return array
491
-	 */
492
-	protected function getUser($uid) {
493
-		// First try local user
494
-		$user = $this->userManager->get($uid);
495
-		if ($user instanceof IUser) {
496
-			return [
497
-				'type' => 'user',
498
-				'id' => $user->getUID(),
499
-				'name' => $user->getDisplayName(),
500
-			];
501
-		}
502
-
503
-		// Then a contact from the addressbook
504
-		if ($this->cloudIdManager->isValidCloudId($uid)) {
505
-			$cloudId = $this->cloudIdManager->resolveCloudId($uid);
506
-			return [
507
-				'type' => 'user',
508
-				'id' => $cloudId->getUser(),
509
-				'name' => $this->getDisplayNameFromAddressBook($cloudId->getDisplayId()),
510
-				'server' => $cloudId->getRemote(),
511
-			];
512
-		}
513
-
514
-		// Fallback to empty dummy data
515
-		return [
516
-			'type' => 'user',
517
-			'id' => $uid,
518
-			'name' => $uid,
519
-		];
520
-	}
521
-
522
-	protected function getDisplayNameFromAddressBook(string $search): string {
523
-		if (isset($this->displayNames[$search])) {
524
-			return $this->displayNames[$search];
525
-		}
526
-
527
-		$addressBookContacts = $this->contactsManager->search($search, ['CLOUD']);
528
-		foreach ($addressBookContacts as $contact) {
529
-			if (isset($contact['isLocalSystemBook'])) {
530
-				continue;
531
-			}
532
-
533
-			if (isset($contact['CLOUD'])) {
534
-				$cloudIds = $contact['CLOUD'];
535
-				if (is_string($cloudIds)) {
536
-					$cloudIds = [$cloudIds];
537
-				}
538
-
539
-				$lowerSearch = strtolower($search);
540
-				foreach ($cloudIds as $cloudId) {
541
-					if (strtolower($cloudId) === $lowerSearch) {
542
-						$this->displayNames[$search] = $contact['FN'] . " ($cloudId)";
543
-						return $this->displayNames[$search];
544
-					}
545
-				}
546
-			}
547
-		}
548
-
549
-		return $search;
550
-	}
47
+    /** @var IFactory */
48
+    protected $languageFactory;
49
+
50
+    /** @var IL10N */
51
+    protected $l;
52
+    /** @var IL10N */
53
+    protected $activityLang;
54
+
55
+    /** @var IURLGenerator */
56
+    protected $url;
57
+
58
+    /** @var IManager */
59
+    protected $activityManager;
60
+
61
+    /** @var IUserManager */
62
+    protected $userManager;
63
+
64
+    /** @var IRootFolder */
65
+    protected $rootFolder;
66
+
67
+    /** @var IEventMerger */
68
+    protected $eventMerger;
69
+
70
+    /** @var ICloudIdManager */
71
+    protected $cloudIdManager;
72
+
73
+    /** @var IContactsManager */
74
+    protected $contactsManager;
75
+
76
+    /** @var string[] cached displayNames - key is the cloud id and value the displayname */
77
+    protected $displayNames = [];
78
+
79
+    protected $fileIsEncrypted = false;
80
+
81
+    public function __construct(IFactory $languageFactory,
82
+                                IURLGenerator $url,
83
+                                IManager $activityManager,
84
+                                IUserManager $userManager,
85
+                                IRootFolder $rootFolder,
86
+                                ICloudIdManager $cloudIdManager,
87
+                                IContactsManager $contactsManager,
88
+                                IEventMerger $eventMerger) {
89
+        $this->languageFactory = $languageFactory;
90
+        $this->url = $url;
91
+        $this->activityManager = $activityManager;
92
+        $this->userManager = $userManager;
93
+        $this->rootFolder = $rootFolder;
94
+        $this->cloudIdManager = $cloudIdManager;
95
+        $this->contactsManager = $contactsManager;
96
+        $this->eventMerger = $eventMerger;
97
+    }
98
+
99
+    /**
100
+     * @param string $language
101
+     * @param IEvent $event
102
+     * @param IEvent|null $previousEvent
103
+     * @return IEvent
104
+     * @throws \InvalidArgumentException
105
+     * @since 11.0.0
106
+     */
107
+    public function parse($language, IEvent $event, IEvent $previousEvent = null) {
108
+        if ($event->getApp() !== 'files') {
109
+            throw new \InvalidArgumentException();
110
+        }
111
+
112
+        $this->l = $this->languageFactory->get('files', $language);
113
+        $this->activityLang = $this->languageFactory->get('activity', $language);
114
+
115
+        if ($this->activityManager->isFormattingFilteredObject()) {
116
+            try {
117
+                return $this->parseShortVersion($event, $previousEvent);
118
+            } catch (\InvalidArgumentException $e) {
119
+                // Ignore and simply use the long version...
120
+            }
121
+        }
122
+
123
+        return $this->parseLongVersion($event, $previousEvent);
124
+    }
125
+
126
+    protected function setIcon(IEvent $event, string $icon, string $app = 'files') {
127
+        if ($this->activityManager->getRequirePNG()) {
128
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath($app, $icon . '.png')));
129
+        } else {
130
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath($app, $icon . '.svg')));
131
+        }
132
+    }
133
+
134
+    /**
135
+     * @param IEvent $event
136
+     * @param IEvent|null $previousEvent
137
+     * @return IEvent
138
+     * @throws \InvalidArgumentException
139
+     * @since 11.0.0
140
+     */
141
+    public function parseShortVersion(IEvent $event, IEvent $previousEvent = null) {
142
+        $parsedParameters = $this->getParameters($event);
143
+
144
+        if ($event->getSubject() === 'created_by') {
145
+            $subject = $this->l->t('Created by {user}');
146
+            $this->setIcon($event, 'add-color');
147
+        } elseif ($event->getSubject() === 'changed_by') {
148
+            $subject = $this->l->t('Changed by {user}');
149
+            $this->setIcon($event, 'change');
150
+        } elseif ($event->getSubject() === 'deleted_by') {
151
+            $subject = $this->l->t('Deleted by {user}');
152
+            $this->setIcon($event, 'delete-color');
153
+        } elseif ($event->getSubject() === 'restored_by') {
154
+            $subject = $this->l->t('Restored by {user}');
155
+            $this->setIcon($event, 'actions/history', 'core');
156
+        } elseif ($event->getSubject() === 'renamed_by') {
157
+            $subject = $this->l->t('Renamed by {user}');
158
+            $this->setIcon($event, 'change');
159
+        } elseif ($event->getSubject() === 'moved_by') {
160
+            $subject = $this->l->t('Moved by {user}');
161
+            $this->setIcon($event, 'change');
162
+        } else {
163
+            throw new \InvalidArgumentException();
164
+        }
165
+
166
+        if (!isset($parsedParameters['user'])) {
167
+            // External user via public link share
168
+            $subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
169
+        }
170
+
171
+        $this->setSubjects($event, $subject, $parsedParameters);
172
+
173
+        return $this->eventMerger->mergeEvents('user', $event, $previousEvent);
174
+    }
175
+
176
+    /**
177
+     * @param IEvent $event
178
+     * @param IEvent|null $previousEvent
179
+     * @return IEvent
180
+     * @throws \InvalidArgumentException
181
+     * @since 11.0.0
182
+     */
183
+    public function parseLongVersion(IEvent $event, IEvent $previousEvent = null) {
184
+        $this->fileIsEncrypted = false;
185
+        $parsedParameters = $this->getParameters($event);
186
+
187
+        if ($event->getSubject() === 'created_self') {
188
+            $subject = $this->l->t('You created {file}');
189
+            if ($this->fileIsEncrypted) {
190
+                $subject = $this->l->t('You created an encrypted file in {file}');
191
+            }
192
+            $this->setIcon($event, 'add-color');
193
+        } elseif ($event->getSubject() === 'created_by') {
194
+            $subject = $this->l->t('{user} created {file}');
195
+            if ($this->fileIsEncrypted) {
196
+                $subject = $this->l->t('{user} created an encrypted file in {file}');
197
+            }
198
+            $this->setIcon($event, 'add-color');
199
+        } elseif ($event->getSubject() === 'created_public') {
200
+            $subject = $this->l->t('{file} was created in a public folder');
201
+            $this->setIcon($event, 'add-color');
202
+        } elseif ($event->getSubject() === 'changed_self') {
203
+            $subject = $this->l->t('You changed {file}');
204
+            if ($this->fileIsEncrypted) {
205
+                $subject = $this->l->t('You changed an encrypted file in {file}');
206
+            }
207
+            $this->setIcon($event, 'change');
208
+        } elseif ($event->getSubject() === 'changed_by') {
209
+            $subject = $this->l->t('{user} changed {file}');
210
+            if ($this->fileIsEncrypted) {
211
+                $subject = $this->l->t('{user} changed an encrypted file in {file}');
212
+            }
213
+            $this->setIcon($event, 'change');
214
+        } elseif ($event->getSubject() === 'deleted_self') {
215
+            $subject = $this->l->t('You deleted {file}');
216
+            if ($this->fileIsEncrypted) {
217
+                $subject = $this->l->t('You deleted an encrypted file in {file}');
218
+            }
219
+            $this->setIcon($event, 'delete-color');
220
+        } elseif ($event->getSubject() === 'deleted_by') {
221
+            $subject = $this->l->t('{user} deleted {file}');
222
+            if ($this->fileIsEncrypted) {
223
+                $subject = $this->l->t('{user} deleted an encrypted file in {file}');
224
+            }
225
+            $this->setIcon($event, 'delete-color');
226
+        } elseif ($event->getSubject() === 'restored_self') {
227
+            $subject = $this->l->t('You restored {file}');
228
+            $this->setIcon($event, 'actions/history', 'core');
229
+        } elseif ($event->getSubject() === 'restored_by') {
230
+            $subject = $this->l->t('{user} restored {file}');
231
+            $this->setIcon($event, 'actions/history', 'core');
232
+        } elseif ($event->getSubject() === 'renamed_self') {
233
+            $subject = $this->l->t('You renamed {oldfile} to {newfile}');
234
+            $this->setIcon($event, 'change');
235
+        } elseif ($event->getSubject() === 'renamed_by') {
236
+            $subject = $this->l->t('{user} renamed {oldfile} to {newfile}');
237
+            $this->setIcon($event, 'change');
238
+        } elseif ($event->getSubject() === 'moved_self') {
239
+            $subject = $this->l->t('You moved {oldfile} to {newfile}');
240
+            $this->setIcon($event, 'change');
241
+        } elseif ($event->getSubject() === 'moved_by') {
242
+            $subject = $this->l->t('{user} moved {oldfile} to {newfile}');
243
+            $this->setIcon($event, 'change');
244
+        } else {
245
+            throw new \InvalidArgumentException();
246
+        }
247
+
248
+        if ($this->fileIsEncrypted) {
249
+            $event->setSubject($event->getSubject() . '_enc', $event->getSubjectParameters());
250
+        }
251
+
252
+        if (!isset($parsedParameters['user'])) {
253
+            // External user via public link share
254
+            $subject = str_replace('{user}', $this->activityLang->t('"remote user"'), $subject);
255
+        }
256
+
257
+        $this->setSubjects($event, $subject, $parsedParameters);
258
+
259
+        if ($event->getSubject() === 'moved_self' || $event->getSubject() === 'moved_by') {
260
+            $event = $this->eventMerger->mergeEvents('oldfile', $event, $previousEvent);
261
+        } else {
262
+            $event = $this->eventMerger->mergeEvents('file', $event, $previousEvent);
263
+        }
264
+
265
+        if ($event->getChildEvent() === null) {
266
+            // Couldn't group by file, maybe we can group by user
267
+            $event = $this->eventMerger->mergeEvents('user', $event, $previousEvent);
268
+        }
269
+
270
+        return $event;
271
+    }
272
+
273
+    protected function setSubjects(IEvent $event, $subject, array $parameters) {
274
+        $placeholders = $replacements = [];
275
+        foreach ($parameters as $placeholder => $parameter) {
276
+            $placeholders[] = '{' . $placeholder . '}';
277
+            if ($parameter['type'] === 'file') {
278
+                $replacements[] = $parameter['path'];
279
+            } else {
280
+                $replacements[] = $parameter['name'];
281
+            }
282
+        }
283
+
284
+        $event->setParsedSubject(str_replace($placeholders, $replacements, $subject))
285
+            ->setRichSubject($subject, $parameters);
286
+    }
287
+
288
+    /**
289
+     * @param IEvent $event
290
+     * @return array
291
+     * @throws \InvalidArgumentException
292
+     */
293
+    protected function getParameters(IEvent $event) {
294
+        $parameters = $event->getSubjectParameters();
295
+        switch ($event->getSubject()) {
296
+            case 'created_self':
297
+            case 'created_public':
298
+            case 'changed_self':
299
+            case 'deleted_self':
300
+            case 'restored_self':
301
+                return [
302
+                    'file' => $this->getFile($parameters[0], $event),
303
+                ];
304
+            case 'created_by':
305
+            case 'changed_by':
306
+            case 'deleted_by':
307
+            case 'restored_by':
308
+                if ($parameters[1] === '') {
309
+                    // External user via public link share
310
+                    return [
311
+                        'file' => $this->getFile($parameters[0], $event),
312
+                    ];
313
+                }
314
+                return [
315
+                    'file' => $this->getFile($parameters[0], $event),
316
+                    'user' => $this->getUser($parameters[1]),
317
+                ];
318
+            case 'renamed_self':
319
+            case 'moved_self':
320
+                return [
321
+                    'newfile' => $this->getFile($parameters[0]),
322
+                    'oldfile' => $this->getFile($parameters[1]),
323
+                ];
324
+            case 'renamed_by':
325
+            case 'moved_by':
326
+                if ($parameters[1] === '') {
327
+                    // External user via public link share
328
+                    return [
329
+                        'newfile' => $this->getFile($parameters[0]),
330
+                        'oldfile' => $this->getFile($parameters[2]),
331
+                    ];
332
+                }
333
+                return [
334
+                    'newfile' => $this->getFile($parameters[0]),
335
+                    'user' => $this->getUser($parameters[1]),
336
+                    'oldfile' => $this->getFile($parameters[2]),
337
+                ];
338
+        }
339
+        return [];
340
+    }
341
+
342
+    /**
343
+     * @param array|string $parameter
344
+     * @param IEvent|null $event
345
+     * @return array
346
+     * @throws \InvalidArgumentException
347
+     */
348
+    protected function getFile($parameter, IEvent $event = null) {
349
+        if (is_array($parameter)) {
350
+            $path = reset($parameter);
351
+            $id = (string) key($parameter);
352
+        } elseif ($event !== null) {
353
+            // Legacy from before ownCloud 8.2
354
+            $path = $parameter;
355
+            $id = $event->getObjectId();
356
+        } else {
357
+            throw new \InvalidArgumentException('Could not generate file parameter');
358
+        }
359
+
360
+        $encryptionContainer = $this->getEndToEndEncryptionContainer($id, $path);
361
+        if ($encryptionContainer instanceof Folder) {
362
+            $this->fileIsEncrypted = true;
363
+            try {
364
+                $fullPath = rtrim($encryptionContainer->getPath(), '/');
365
+                // Remove /user/files/...
366
+                [,,, $path] = explode('/', $fullPath, 4);
367
+                if (!$path) {
368
+                    throw new InvalidPathException('Path could not be split correctly');
369
+                }
370
+
371
+                return [
372
+                    'type' => 'file',
373
+                    'id' => $encryptionContainer->getId(),
374
+                    'name' => $encryptionContainer->getName(),
375
+                    'path' => $path,
376
+                    'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $encryptionContainer->getId()]),
377
+                ];
378
+            } catch (\Exception $e) {
379
+                // fall back to the normal one
380
+                $this->fileIsEncrypted = false;
381
+            }
382
+        }
383
+
384
+        return [
385
+            'type' => 'file',
386
+            'id' => $id,
387
+            'name' => basename($path),
388
+            'path' => trim($path, '/'),
389
+            'link' => $this->url->linkToRouteAbsolute('files.viewcontroller.showFile', ['fileid' => $id]),
390
+        ];
391
+    }
392
+
393
+    protected $fileEncrypted = [];
394
+
395
+    /**
396
+     * Check if a file is end2end encrypted
397
+     * @param int $fileId
398
+     * @param string $path
399
+     * @return Folder|null
400
+     */
401
+    protected function getEndToEndEncryptionContainer($fileId, $path) {
402
+        if (isset($this->fileEncrypted[$fileId])) {
403
+            return $this->fileEncrypted[$fileId];
404
+        }
405
+
406
+        $fileName = basename($path);
407
+        if (!preg_match('/^[0-9a-fA-F]{32}$/', $fileName)) {
408
+            $this->fileEncrypted[$fileId] = false;
409
+            return $this->fileEncrypted[$fileId];
410
+        }
411
+
412
+        $userFolder = $this->rootFolder->getUserFolder($this->activityManager->getCurrentUserId());
413
+        $files = $userFolder->getById($fileId);
414
+        if (empty($files)) {
415
+            try {
416
+                // Deleted, try with parent
417
+                $file = $this->findExistingParent($userFolder, dirname($path));
418
+            } catch (NotFoundException $e) {
419
+                return null;
420
+            }
421
+
422
+            if (!$file instanceof Folder || !$file->isEncrypted()) {
423
+                return null;
424
+            }
425
+
426
+            $this->fileEncrypted[$fileId] = $file;
427
+            return $file;
428
+        }
429
+
430
+        $file = array_shift($files);
431
+
432
+        if ($file instanceof Folder && $file->isEncrypted()) {
433
+            // If the folder is encrypted, it is the Container,
434
+            // but can be the name is just fine.
435
+            $this->fileEncrypted[$fileId] = true;
436
+            return null;
437
+        }
438
+
439
+        $this->fileEncrypted[$fileId] = $this->getParentEndToEndEncryptionContainer($userFolder, $file);
440
+        return $this->fileEncrypted[$fileId];
441
+    }
442
+
443
+    /**
444
+     * @param Folder $userFolder
445
+     * @param string $path
446
+     * @return Folder
447
+     * @throws NotFoundException
448
+     */
449
+    protected function findExistingParent(Folder $userFolder, $path) {
450
+        if ($path === '/') {
451
+            throw new NotFoundException('Reached the root');
452
+        }
453
+
454
+        try {
455
+            $folder = $userFolder->get(dirname($path));
456
+        } catch (NotFoundException $e) {
457
+            return $this->findExistingParent($userFolder, dirname($path));
458
+        }
459
+
460
+        return $folder;
461
+    }
462
+
463
+    /**
464
+     * Check all parents until the user's root folder if one is encrypted
465
+     *
466
+     * @param Folder $userFolder
467
+     * @param Node $file
468
+     * @return Node|null
469
+     */
470
+    protected function getParentEndToEndEncryptionContainer(Folder $userFolder, Node $file) {
471
+        try {
472
+            $parent = $file->getParent();
473
+
474
+            if ($userFolder->getId() === $parent->getId()) {
475
+                return null;
476
+            }
477
+        } catch (\Exception $e) {
478
+            return null;
479
+        }
480
+
481
+        if ($parent->isEncrypted()) {
482
+            return $parent;
483
+        }
484
+
485
+        return $this->getParentEndToEndEncryptionContainer($userFolder, $parent);
486
+    }
487
+
488
+    /**
489
+     * @param string $uid
490
+     * @return array
491
+     */
492
+    protected function getUser($uid) {
493
+        // First try local user
494
+        $user = $this->userManager->get($uid);
495
+        if ($user instanceof IUser) {
496
+            return [
497
+                'type' => 'user',
498
+                'id' => $user->getUID(),
499
+                'name' => $user->getDisplayName(),
500
+            ];
501
+        }
502
+
503
+        // Then a contact from the addressbook
504
+        if ($this->cloudIdManager->isValidCloudId($uid)) {
505
+            $cloudId = $this->cloudIdManager->resolveCloudId($uid);
506
+            return [
507
+                'type' => 'user',
508
+                'id' => $cloudId->getUser(),
509
+                'name' => $this->getDisplayNameFromAddressBook($cloudId->getDisplayId()),
510
+                'server' => $cloudId->getRemote(),
511
+            ];
512
+        }
513
+
514
+        // Fallback to empty dummy data
515
+        return [
516
+            'type' => 'user',
517
+            'id' => $uid,
518
+            'name' => $uid,
519
+        ];
520
+    }
521
+
522
+    protected function getDisplayNameFromAddressBook(string $search): string {
523
+        if (isset($this->displayNames[$search])) {
524
+            return $this->displayNames[$search];
525
+        }
526
+
527
+        $addressBookContacts = $this->contactsManager->search($search, ['CLOUD']);
528
+        foreach ($addressBookContacts as $contact) {
529
+            if (isset($contact['isLocalSystemBook'])) {
530
+                continue;
531
+            }
532
+
533
+            if (isset($contact['CLOUD'])) {
534
+                $cloudIds = $contact['CLOUD'];
535
+                if (is_string($cloudIds)) {
536
+                    $cloudIds = [$cloudIds];
537
+                }
538
+
539
+                $lowerSearch = strtolower($search);
540
+                foreach ($cloudIds as $cloudId) {
541
+                    if (strtolower($cloudId) === $lowerSearch) {
542
+                        $this->displayNames[$search] = $contact['FN'] . " ($cloudId)";
543
+                        return $this->displayNames[$search];
544
+                    }
545
+                }
546
+            }
547
+        }
548
+
549
+        return $search;
550
+    }
551 551
 }
Please login to merge, or discard this patch.
apps/systemtags/lib/Activity/Provider.php 2 patches
Indentation   +335 added lines, -335 removed lines patch added patch discarded remove patch
@@ -34,339 +34,339 @@
 block discarded – undo
34 34
 use OCP\L10N\IFactory;
35 35
 
36 36
 class Provider implements IProvider {
37
-	public const CREATE_TAG = 'create_tag';
38
-	public const UPDATE_TAG = 'update_tag';
39
-	public const DELETE_TAG = 'delete_tag';
40
-
41
-	public const ASSIGN_TAG = 'assign_tag';
42
-	public const UNASSIGN_TAG = 'unassign_tag';
43
-
44
-	/** @var IFactory */
45
-	protected $languageFactory;
46
-
47
-	/** @var IL10N */
48
-	protected $l;
49
-
50
-	/** @var IURLGenerator */
51
-	protected $url;
52
-
53
-	/** @var IManager */
54
-	protected $activityManager;
55
-
56
-	/** @var IUserManager */
57
-	protected $userManager;
58
-
59
-	/** @var string[] */
60
-	protected $displayNames = [];
61
-
62
-	/**
63
-	 * @param IFactory $languageFactory
64
-	 * @param IURLGenerator $url
65
-	 * @param IManager $activityManager
66
-	 * @param IUserManager $userManager
67
-	 */
68
-	public function __construct(IFactory $languageFactory, IURLGenerator $url, IManager $activityManager, IUserManager $userManager) {
69
-		$this->languageFactory = $languageFactory;
70
-		$this->url = $url;
71
-		$this->activityManager = $activityManager;
72
-		$this->userManager = $userManager;
73
-	}
74
-
75
-	/**
76
-	 * @param string $language
77
-	 * @param IEvent $event
78
-	 * @param IEvent|null $previousEvent
79
-	 * @return IEvent
80
-	 * @throws \InvalidArgumentException
81
-	 * @since 11.0.0
82
-	 */
83
-	public function parse($language, IEvent $event, IEvent $previousEvent = null) {
84
-		if ($event->getApp() !== 'systemtags') {
85
-			throw new \InvalidArgumentException();
86
-		}
87
-
88
-		$this->l = $this->languageFactory->get('systemtags', $language);
89
-
90
-		if ($this->activityManager->isFormattingFilteredObject()) {
91
-			try {
92
-				return $this->parseShortVersion($event);
93
-			} catch (\InvalidArgumentException $e) {
94
-				// Ignore and simply use the long version...
95
-			}
96
-		}
97
-
98
-		return $this->parseLongVersion($event);
99
-	}
100
-
101
-	/**
102
-	 * @param IEvent $event
103
-	 * @return IEvent
104
-	 * @throws \InvalidArgumentException
105
-	 * @since 11.0.0
106
-	 */
107
-	public function parseShortVersion(IEvent $event) {
108
-		$parsedParameters = $this->getParameters($event);
109
-
110
-		if ($this->activityManager->getRequirePNG()) {
111
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/tag.png')));
112
-		} else {
113
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/tag.svg')));
114
-		}
115
-
116
-		if ($event->getSubject() === self::ASSIGN_TAG) {
117
-			if ($parsedParameters['actor']['id'] === '') {
118
-				$event->setParsedSubject($this->l->t('System tag %1$s added by the system', [
119
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
120
-				]))
121
-					->setRichSubject($this->l->t('Added system tag {systemtag}'), [
122
-						'systemtag' => $parsedParameters['systemtag'],
123
-					]);
124
-			} elseif ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
125
-				$event->setParsedSubject($this->l->t('Added system tag %1$s', [
126
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
127
-				]))
128
-					->setRichSubject($this->l->t('Added system tag {systemtag}'), [
129
-						'systemtag' => $parsedParameters['systemtag'],
130
-					]);
131
-			} else {
132
-				$event->setParsedSubject($this->l->t('%1$s added system tag %2$s', [
133
-					$parsedParameters['actor']['name'],
134
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
135
-				]))
136
-					->setRichSubject($this->l->t('{actor} added system tag {systemtag}'), [
137
-						'actor' => $parsedParameters['actor'],
138
-						'systemtag' => $parsedParameters['systemtag'],
139
-					]);
140
-			}
141
-		} elseif ($event->getSubject() === self::UNASSIGN_TAG) {
142
-			if ($parsedParameters['actor']['id'] === '') {
143
-				$event->setParsedSubject($this->l->t('System tag %1$s removed by the system', [
144
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
145
-				]))
146
-					->setRichSubject($this->l->t('Removed system tag {systemtag}'), [
147
-						'systemtag' => $parsedParameters['systemtag'],
148
-					]);
149
-			} elseif ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
150
-				$event->setParsedSubject($this->l->t('Removed system tag %1$s', [
151
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
152
-				]))
153
-					->setRichSubject($this->l->t('Removed system tag {systemtag}'), [
154
-						'systemtag' => $parsedParameters['systemtag'],
155
-					]);
156
-			} else {
157
-				$event->setParsedSubject($this->l->t('%1$s removed system tag %2$s', [
158
-					$parsedParameters['actor']['name'],
159
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
160
-				]))
161
-					->setRichSubject($this->l->t('{actor} removed system tag {systemtag}'), [
162
-						'actor' => $parsedParameters['actor'],
163
-						'systemtag' => $parsedParameters['systemtag'],
164
-					]);
165
-			}
166
-		} else {
167
-			throw new \InvalidArgumentException();
168
-		}
169
-
170
-		return $event;
171
-	}
172
-
173
-	/**
174
-	 * @param IEvent $event
175
-	 * @return IEvent
176
-	 * @throws \InvalidArgumentException
177
-	 * @since 11.0.0
178
-	 */
179
-	public function parseLongVersion(IEvent $event) {
180
-		$parsedParameters = $this->getParameters($event);
181
-
182
-		if ($this->activityManager->getRequirePNG()) {
183
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/tag.png')));
184
-		} else {
185
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/tag.svg')));
186
-		}
187
-
188
-		if ($event->getSubject() === self::CREATE_TAG) {
189
-			if ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
190
-				$event->setParsedSubject($this->l->t('You created system tag %1$s', [
191
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
192
-				]))
193
-					->setRichSubject($this->l->t('You created system tag {systemtag}'), $parsedParameters);
194
-			} else {
195
-				$event->setParsedSubject($this->l->t('%1$s created system tag %2$s', [
196
-					$parsedParameters['actor']['name'],
197
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
198
-				]))
199
-					->setRichSubject($this->l->t('{actor} created system tag {systemtag}'), $parsedParameters);
200
-			}
201
-		} elseif ($event->getSubject() === self::DELETE_TAG) {
202
-			if ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
203
-				$event->setParsedSubject($this->l->t('You deleted system tag %1$s', [
204
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
205
-				]))
206
-					->setRichSubject($this->l->t('You deleted system tag {systemtag}'), $parsedParameters);
207
-			} else {
208
-				$event->setParsedSubject($this->l->t('%1$s deleted system tag %2$s', [
209
-					$parsedParameters['actor']['name'],
210
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
211
-				]))
212
-					->setRichSubject($this->l->t('{actor} deleted system tag {systemtag}'), $parsedParameters);
213
-			}
214
-		} elseif ($event->getSubject() === self::UPDATE_TAG) {
215
-			if ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
216
-				$event->setParsedSubject($this->l->t('You updated system tag %2$s to %1$s', [
217
-					$this->generatePlainSystemTag($parsedParameters['newsystemtag']),
218
-					$this->generatePlainSystemTag($parsedParameters['oldsystemtag']),
219
-				]))
220
-					->setRichSubject($this->l->t('You updated system tag {oldsystemtag} to {newsystemtag}'), $parsedParameters);
221
-			} else {
222
-				$event->setParsedSubject($this->l->t('%1$s updated system tag %3$s to %2$s', [
223
-					$parsedParameters['actor']['name'],
224
-					$this->generatePlainSystemTag($parsedParameters['newsystemtag']),
225
-					$this->generatePlainSystemTag($parsedParameters['oldsystemtag']),
226
-				]))
227
-					->setRichSubject($this->l->t('{actor} updated system tag {oldsystemtag} to {newsystemtag}'), $parsedParameters);
228
-			}
229
-		} elseif ($event->getSubject() === self::ASSIGN_TAG) {
230
-			if ($parsedParameters['actor']['id'] === '') {
231
-				unset($parsedParameters['actor']);
232
-				$event->setParsedSubject($this->l->t('System tag %2$s was added to %1$s by the system', [
233
-					$parsedParameters['file']['path'],
234
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
235
-				]))
236
-					->setRichSubject($this->l->t('System tag {systemtag} was added to {file} by the system'), $parsedParameters);
237
-			} elseif ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
238
-				$event->setParsedSubject($this->l->t('You added system tag %2$s to %1$s', [
239
-					$parsedParameters['file']['path'],
240
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
241
-				]))
242
-					->setRichSubject($this->l->t('You added system tag {systemtag} to {file}'), $parsedParameters);
243
-			} else {
244
-				$event->setParsedSubject($this->l->t('%1$s added system tag %3$s to %2$s', [
245
-					$parsedParameters['actor']['name'],
246
-					$parsedParameters['file']['path'],
247
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
248
-				]))
249
-					->setRichSubject($this->l->t('{actor} added system tag {systemtag} to {file}'), $parsedParameters);
250
-			}
251
-		} elseif ($event->getSubject() === self::UNASSIGN_TAG) {
252
-			if ($parsedParameters['actor']['id'] === '') {
253
-				unset($parsedParameters['actor']);
254
-				$event->setParsedSubject($this->l->t('System tag %2$s was removed from %1$s by the system', [
255
-					$parsedParameters['file']['path'],
256
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
257
-				]))
258
-					->setRichSubject($this->l->t('System tag {systemtag} was removed from {file} by the system'), $parsedParameters);
259
-			} elseif ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
260
-				$event->setParsedSubject($this->l->t('You removed system tag %2$s from %1$s', [
261
-					$parsedParameters['file']['path'],
262
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
263
-				]))
264
-					->setRichSubject($this->l->t('You removed system tag {systemtag} from {file}'), $parsedParameters);
265
-			} else {
266
-				$event->setParsedSubject($this->l->t('%1$s removed system tag %3$s from %2$s', [
267
-					$parsedParameters['actor']['name'],
268
-					$parsedParameters['file']['path'],
269
-					$this->generatePlainSystemTag($parsedParameters['systemtag']),
270
-				]))
271
-					->setRichSubject($this->l->t('{actor} removed system tag {systemtag} from {file}'), $parsedParameters);
272
-			}
273
-		} else {
274
-			throw new \InvalidArgumentException();
275
-		}
276
-
277
-		return $event;
278
-	}
279
-
280
-	protected function getParameters(IEvent $event) {
281
-		$subject = $event->getSubject();
282
-		$parameters = $event->getSubjectParameters();
283
-
284
-		switch ($subject) {
285
-			case self::CREATE_TAG:
286
-			case self::DELETE_TAG:
287
-				return [
288
-					'actor' => $this->getUserParameter((string) $parameters[0]),
289
-					'systemtag' => $this->getSystemTagParameter($parameters[1]),
290
-				];
291
-			case self::UPDATE_TAG:
292
-				return [
293
-					'actor' => $this->getUserParameter((string) $parameters[0]),
294
-					'newsystemtag' => $this->getSystemTagParameter($parameters[1]),
295
-					'oldsystemtag' => $this->getSystemTagParameter($parameters[2]),
296
-				];
297
-			case self::ASSIGN_TAG:
298
-			case self::UNASSIGN_TAG:
299
-				return [
300
-					'actor' => $this->getUserParameter((string) $parameters[0]),
301
-					'file' => $this->getFileParameter($event->getObjectId(), $parameters[1]),
302
-					'systemtag' => $this->getSystemTagParameter($parameters[2]),
303
-				];
304
-		}
305
-		return [];
306
-	}
307
-
308
-	protected function getFileParameter($id, $path) {
309
-		return [
310
-			'type' => 'file',
311
-			'id' => $id,
312
-			'name' => basename($path),
313
-			'path' => trim($path, '/'),
314
-		];
315
-	}
316
-
317
-	protected function getSystemTagParameter($parameter) {
318
-		$tagData = json_decode($parameter, true);
319
-		if ($tagData === null) {
320
-			[$name, $status] = explode('|||', substr($parameter, 3, -3));
321
-			$tagData = [
322
-				'id' => 0,// No way to recover the ID
323
-				'name' => $name,
324
-				'assignable' => $status === 'assignable',
325
-				'visible' => $status !== 'invisible',
326
-			];
327
-		}
328
-
329
-		return [
330
-			'type' => 'systemtag',
331
-			'id' => (int) $tagData['id'],
332
-			'name' => $tagData['name'],
333
-			'assignable' => $tagData['assignable'] ? '1' : '0',
334
-			'visibility' => $tagData['visible'] ? '1' : '0',
335
-		];
336
-	}
337
-
338
-	protected function getUserParameter($uid) {
339
-		if (!isset($this->displayNames[$uid])) {
340
-			$this->displayNames[$uid] = $this->getDisplayName($uid);
341
-		}
342
-
343
-		return [
344
-			'type' => 'user',
345
-			'id' => $uid,
346
-			'name' => $this->displayNames[$uid],
347
-		];
348
-	}
349
-
350
-	protected function generatePlainSystemTag(array $parameter) {
351
-		if ($parameter['assignable'] === '1') {
352
-			return $parameter['name'];
353
-		} elseif ($parameter['visibility'] === '1') {
354
-			return $this->l->t('%s (restricted)', $parameter['name']);
355
-		} else {
356
-			return $this->l->t('%s (invisible)', $parameter['name']);
357
-		}
358
-	}
359
-
360
-	/**
361
-	 * @param string $uid
362
-	 * @return string
363
-	 */
364
-	protected function getDisplayName($uid) {
365
-		$user = $this->userManager->get($uid);
366
-		if ($user instanceof IUser) {
367
-			return $user->getDisplayName();
368
-		} else {
369
-			return $uid;
370
-		}
371
-	}
37
+    public const CREATE_TAG = 'create_tag';
38
+    public const UPDATE_TAG = 'update_tag';
39
+    public const DELETE_TAG = 'delete_tag';
40
+
41
+    public const ASSIGN_TAG = 'assign_tag';
42
+    public const UNASSIGN_TAG = 'unassign_tag';
43
+
44
+    /** @var IFactory */
45
+    protected $languageFactory;
46
+
47
+    /** @var IL10N */
48
+    protected $l;
49
+
50
+    /** @var IURLGenerator */
51
+    protected $url;
52
+
53
+    /** @var IManager */
54
+    protected $activityManager;
55
+
56
+    /** @var IUserManager */
57
+    protected $userManager;
58
+
59
+    /** @var string[] */
60
+    protected $displayNames = [];
61
+
62
+    /**
63
+     * @param IFactory $languageFactory
64
+     * @param IURLGenerator $url
65
+     * @param IManager $activityManager
66
+     * @param IUserManager $userManager
67
+     */
68
+    public function __construct(IFactory $languageFactory, IURLGenerator $url, IManager $activityManager, IUserManager $userManager) {
69
+        $this->languageFactory = $languageFactory;
70
+        $this->url = $url;
71
+        $this->activityManager = $activityManager;
72
+        $this->userManager = $userManager;
73
+    }
74
+
75
+    /**
76
+     * @param string $language
77
+     * @param IEvent $event
78
+     * @param IEvent|null $previousEvent
79
+     * @return IEvent
80
+     * @throws \InvalidArgumentException
81
+     * @since 11.0.0
82
+     */
83
+    public function parse($language, IEvent $event, IEvent $previousEvent = null) {
84
+        if ($event->getApp() !== 'systemtags') {
85
+            throw new \InvalidArgumentException();
86
+        }
87
+
88
+        $this->l = $this->languageFactory->get('systemtags', $language);
89
+
90
+        if ($this->activityManager->isFormattingFilteredObject()) {
91
+            try {
92
+                return $this->parseShortVersion($event);
93
+            } catch (\InvalidArgumentException $e) {
94
+                // Ignore and simply use the long version...
95
+            }
96
+        }
97
+
98
+        return $this->parseLongVersion($event);
99
+    }
100
+
101
+    /**
102
+     * @param IEvent $event
103
+     * @return IEvent
104
+     * @throws \InvalidArgumentException
105
+     * @since 11.0.0
106
+     */
107
+    public function parseShortVersion(IEvent $event) {
108
+        $parsedParameters = $this->getParameters($event);
109
+
110
+        if ($this->activityManager->getRequirePNG()) {
111
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/tag.png')));
112
+        } else {
113
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/tag.svg')));
114
+        }
115
+
116
+        if ($event->getSubject() === self::ASSIGN_TAG) {
117
+            if ($parsedParameters['actor']['id'] === '') {
118
+                $event->setParsedSubject($this->l->t('System tag %1$s added by the system', [
119
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
120
+                ]))
121
+                    ->setRichSubject($this->l->t('Added system tag {systemtag}'), [
122
+                        'systemtag' => $parsedParameters['systemtag'],
123
+                    ]);
124
+            } elseif ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
125
+                $event->setParsedSubject($this->l->t('Added system tag %1$s', [
126
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
127
+                ]))
128
+                    ->setRichSubject($this->l->t('Added system tag {systemtag}'), [
129
+                        'systemtag' => $parsedParameters['systemtag'],
130
+                    ]);
131
+            } else {
132
+                $event->setParsedSubject($this->l->t('%1$s added system tag %2$s', [
133
+                    $parsedParameters['actor']['name'],
134
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
135
+                ]))
136
+                    ->setRichSubject($this->l->t('{actor} added system tag {systemtag}'), [
137
+                        'actor' => $parsedParameters['actor'],
138
+                        'systemtag' => $parsedParameters['systemtag'],
139
+                    ]);
140
+            }
141
+        } elseif ($event->getSubject() === self::UNASSIGN_TAG) {
142
+            if ($parsedParameters['actor']['id'] === '') {
143
+                $event->setParsedSubject($this->l->t('System tag %1$s removed by the system', [
144
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
145
+                ]))
146
+                    ->setRichSubject($this->l->t('Removed system tag {systemtag}'), [
147
+                        'systemtag' => $parsedParameters['systemtag'],
148
+                    ]);
149
+            } elseif ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
150
+                $event->setParsedSubject($this->l->t('Removed system tag %1$s', [
151
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
152
+                ]))
153
+                    ->setRichSubject($this->l->t('Removed system tag {systemtag}'), [
154
+                        'systemtag' => $parsedParameters['systemtag'],
155
+                    ]);
156
+            } else {
157
+                $event->setParsedSubject($this->l->t('%1$s removed system tag %2$s', [
158
+                    $parsedParameters['actor']['name'],
159
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
160
+                ]))
161
+                    ->setRichSubject($this->l->t('{actor} removed system tag {systemtag}'), [
162
+                        'actor' => $parsedParameters['actor'],
163
+                        'systemtag' => $parsedParameters['systemtag'],
164
+                    ]);
165
+            }
166
+        } else {
167
+            throw new \InvalidArgumentException();
168
+        }
169
+
170
+        return $event;
171
+    }
172
+
173
+    /**
174
+     * @param IEvent $event
175
+     * @return IEvent
176
+     * @throws \InvalidArgumentException
177
+     * @since 11.0.0
178
+     */
179
+    public function parseLongVersion(IEvent $event) {
180
+        $parsedParameters = $this->getParameters($event);
181
+
182
+        if ($this->activityManager->getRequirePNG()) {
183
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/tag.png')));
184
+        } else {
185
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/tag.svg')));
186
+        }
187
+
188
+        if ($event->getSubject() === self::CREATE_TAG) {
189
+            if ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
190
+                $event->setParsedSubject($this->l->t('You created system tag %1$s', [
191
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
192
+                ]))
193
+                    ->setRichSubject($this->l->t('You created system tag {systemtag}'), $parsedParameters);
194
+            } else {
195
+                $event->setParsedSubject($this->l->t('%1$s created system tag %2$s', [
196
+                    $parsedParameters['actor']['name'],
197
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
198
+                ]))
199
+                    ->setRichSubject($this->l->t('{actor} created system tag {systemtag}'), $parsedParameters);
200
+            }
201
+        } elseif ($event->getSubject() === self::DELETE_TAG) {
202
+            if ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
203
+                $event->setParsedSubject($this->l->t('You deleted system tag %1$s', [
204
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
205
+                ]))
206
+                    ->setRichSubject($this->l->t('You deleted system tag {systemtag}'), $parsedParameters);
207
+            } else {
208
+                $event->setParsedSubject($this->l->t('%1$s deleted system tag %2$s', [
209
+                    $parsedParameters['actor']['name'],
210
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
211
+                ]))
212
+                    ->setRichSubject($this->l->t('{actor} deleted system tag {systemtag}'), $parsedParameters);
213
+            }
214
+        } elseif ($event->getSubject() === self::UPDATE_TAG) {
215
+            if ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
216
+                $event->setParsedSubject($this->l->t('You updated system tag %2$s to %1$s', [
217
+                    $this->generatePlainSystemTag($parsedParameters['newsystemtag']),
218
+                    $this->generatePlainSystemTag($parsedParameters['oldsystemtag']),
219
+                ]))
220
+                    ->setRichSubject($this->l->t('You updated system tag {oldsystemtag} to {newsystemtag}'), $parsedParameters);
221
+            } else {
222
+                $event->setParsedSubject($this->l->t('%1$s updated system tag %3$s to %2$s', [
223
+                    $parsedParameters['actor']['name'],
224
+                    $this->generatePlainSystemTag($parsedParameters['newsystemtag']),
225
+                    $this->generatePlainSystemTag($parsedParameters['oldsystemtag']),
226
+                ]))
227
+                    ->setRichSubject($this->l->t('{actor} updated system tag {oldsystemtag} to {newsystemtag}'), $parsedParameters);
228
+            }
229
+        } elseif ($event->getSubject() === self::ASSIGN_TAG) {
230
+            if ($parsedParameters['actor']['id'] === '') {
231
+                unset($parsedParameters['actor']);
232
+                $event->setParsedSubject($this->l->t('System tag %2$s was added to %1$s by the system', [
233
+                    $parsedParameters['file']['path'],
234
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
235
+                ]))
236
+                    ->setRichSubject($this->l->t('System tag {systemtag} was added to {file} by the system'), $parsedParameters);
237
+            } elseif ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
238
+                $event->setParsedSubject($this->l->t('You added system tag %2$s to %1$s', [
239
+                    $parsedParameters['file']['path'],
240
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
241
+                ]))
242
+                    ->setRichSubject($this->l->t('You added system tag {systemtag} to {file}'), $parsedParameters);
243
+            } else {
244
+                $event->setParsedSubject($this->l->t('%1$s added system tag %3$s to %2$s', [
245
+                    $parsedParameters['actor']['name'],
246
+                    $parsedParameters['file']['path'],
247
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
248
+                ]))
249
+                    ->setRichSubject($this->l->t('{actor} added system tag {systemtag} to {file}'), $parsedParameters);
250
+            }
251
+        } elseif ($event->getSubject() === self::UNASSIGN_TAG) {
252
+            if ($parsedParameters['actor']['id'] === '') {
253
+                unset($parsedParameters['actor']);
254
+                $event->setParsedSubject($this->l->t('System tag %2$s was removed from %1$s by the system', [
255
+                    $parsedParameters['file']['path'],
256
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
257
+                ]))
258
+                    ->setRichSubject($this->l->t('System tag {systemtag} was removed from {file} by the system'), $parsedParameters);
259
+            } elseif ($parsedParameters['actor']['id'] === $this->activityManager->getCurrentUserId()) {
260
+                $event->setParsedSubject($this->l->t('You removed system tag %2$s from %1$s', [
261
+                    $parsedParameters['file']['path'],
262
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
263
+                ]))
264
+                    ->setRichSubject($this->l->t('You removed system tag {systemtag} from {file}'), $parsedParameters);
265
+            } else {
266
+                $event->setParsedSubject($this->l->t('%1$s removed system tag %3$s from %2$s', [
267
+                    $parsedParameters['actor']['name'],
268
+                    $parsedParameters['file']['path'],
269
+                    $this->generatePlainSystemTag($parsedParameters['systemtag']),
270
+                ]))
271
+                    ->setRichSubject($this->l->t('{actor} removed system tag {systemtag} from {file}'), $parsedParameters);
272
+            }
273
+        } else {
274
+            throw new \InvalidArgumentException();
275
+        }
276
+
277
+        return $event;
278
+    }
279
+
280
+    protected function getParameters(IEvent $event) {
281
+        $subject = $event->getSubject();
282
+        $parameters = $event->getSubjectParameters();
283
+
284
+        switch ($subject) {
285
+            case self::CREATE_TAG:
286
+            case self::DELETE_TAG:
287
+                return [
288
+                    'actor' => $this->getUserParameter((string) $parameters[0]),
289
+                    'systemtag' => $this->getSystemTagParameter($parameters[1]),
290
+                ];
291
+            case self::UPDATE_TAG:
292
+                return [
293
+                    'actor' => $this->getUserParameter((string) $parameters[0]),
294
+                    'newsystemtag' => $this->getSystemTagParameter($parameters[1]),
295
+                    'oldsystemtag' => $this->getSystemTagParameter($parameters[2]),
296
+                ];
297
+            case self::ASSIGN_TAG:
298
+            case self::UNASSIGN_TAG:
299
+                return [
300
+                    'actor' => $this->getUserParameter((string) $parameters[0]),
301
+                    'file' => $this->getFileParameter($event->getObjectId(), $parameters[1]),
302
+                    'systemtag' => $this->getSystemTagParameter($parameters[2]),
303
+                ];
304
+        }
305
+        return [];
306
+    }
307
+
308
+    protected function getFileParameter($id, $path) {
309
+        return [
310
+            'type' => 'file',
311
+            'id' => $id,
312
+            'name' => basename($path),
313
+            'path' => trim($path, '/'),
314
+        ];
315
+    }
316
+
317
+    protected function getSystemTagParameter($parameter) {
318
+        $tagData = json_decode($parameter, true);
319
+        if ($tagData === null) {
320
+            [$name, $status] = explode('|||', substr($parameter, 3, -3));
321
+            $tagData = [
322
+                'id' => 0,// No way to recover the ID
323
+                'name' => $name,
324
+                'assignable' => $status === 'assignable',
325
+                'visible' => $status !== 'invisible',
326
+            ];
327
+        }
328
+
329
+        return [
330
+            'type' => 'systemtag',
331
+            'id' => (int) $tagData['id'],
332
+            'name' => $tagData['name'],
333
+            'assignable' => $tagData['assignable'] ? '1' : '0',
334
+            'visibility' => $tagData['visible'] ? '1' : '0',
335
+        ];
336
+    }
337
+
338
+    protected function getUserParameter($uid) {
339
+        if (!isset($this->displayNames[$uid])) {
340
+            $this->displayNames[$uid] = $this->getDisplayName($uid);
341
+        }
342
+
343
+        return [
344
+            'type' => 'user',
345
+            'id' => $uid,
346
+            'name' => $this->displayNames[$uid],
347
+        ];
348
+    }
349
+
350
+    protected function generatePlainSystemTag(array $parameter) {
351
+        if ($parameter['assignable'] === '1') {
352
+            return $parameter['name'];
353
+        } elseif ($parameter['visibility'] === '1') {
354
+            return $this->l->t('%s (restricted)', $parameter['name']);
355
+        } else {
356
+            return $this->l->t('%s (invisible)', $parameter['name']);
357
+        }
358
+    }
359
+
360
+    /**
361
+     * @param string $uid
362
+     * @return string
363
+     */
364
+    protected function getDisplayName($uid) {
365
+        $user = $this->userManager->get($uid);
366
+        if ($user instanceof IUser) {
367
+            return $user->getDisplayName();
368
+        } else {
369
+            return $uid;
370
+        }
371
+    }
372 372
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -319,7 +319,7 @@
 block discarded – undo
319 319
 		if ($tagData === null) {
320 320
 			[$name, $status] = explode('|||', substr($parameter, 3, -3));
321 321
 			$tagData = [
322
-				'id' => 0,// No way to recover the ID
322
+				'id' => 0, // No way to recover the ID
323 323
 				'name' => $name,
324 324
 				'assignable' => $status === 'assignable',
325 325
 				'visible' => $status !== 'invisible',
Please login to merge, or discard this patch.
apps/dav/lib/Files/RootCollection.php 1 patch
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -33,33 +33,33 @@
 block discarded – undo
33 33
 
34 34
 class RootCollection extends AbstractPrincipalCollection {
35 35
 
36
-	/**
37
-	 * This method returns a node for a principal.
38
-	 *
39
-	 * The passed array contains principal information, and is guaranteed to
40
-	 * at least contain a uri item. Other properties may or may not be
41
-	 * supplied by the authentication backend.
42
-	 *
43
-	 * @param array $principalInfo
44
-	 * @return INode
45
-	 */
46
-	public function getChildForPrincipal(array $principalInfo) {
47
-		[,$name] = \Sabre\Uri\split($principalInfo['uri']);
48
-		$user = \OC::$server->getUserSession()->getUser();
49
-		if (is_null($user) || $name !== $user->getUID()) {
50
-			// a user is only allowed to see their own home contents, so in case another collection
51
-			// is accessed, we return a simple empty collection for now
52
-			// in the future this could be considered to be used for accessing shared files
53
-			return new SimpleCollection($name);
54
-		}
55
-		$userFolder = \OC::$server->getUserFolder();
56
-		if (!($userFolder instanceof FileInfo)) {
57
-			throw new \Exception('Home does not exist');
58
-		}
59
-		return new FilesHome($principalInfo, $userFolder);
60
-	}
36
+    /**
37
+     * This method returns a node for a principal.
38
+     *
39
+     * The passed array contains principal information, and is guaranteed to
40
+     * at least contain a uri item. Other properties may or may not be
41
+     * supplied by the authentication backend.
42
+     *
43
+     * @param array $principalInfo
44
+     * @return INode
45
+     */
46
+    public function getChildForPrincipal(array $principalInfo) {
47
+        [,$name] = \Sabre\Uri\split($principalInfo['uri']);
48
+        $user = \OC::$server->getUserSession()->getUser();
49
+        if (is_null($user) || $name !== $user->getUID()) {
50
+            // a user is only allowed to see their own home contents, so in case another collection
51
+            // is accessed, we return a simple empty collection for now
52
+            // in the future this could be considered to be used for accessing shared files
53
+            return new SimpleCollection($name);
54
+        }
55
+        $userFolder = \OC::$server->getUserFolder();
56
+        if (!($userFolder instanceof FileInfo)) {
57
+            throw new \Exception('Home does not exist');
58
+        }
59
+        return new FilesHome($principalInfo, $userFolder);
60
+    }
61 61
 
62
-	public function getName() {
63
-		return 'files';
64
-	}
62
+    public function getName() {
63
+        return 'files';
64
+    }
65 65
 }
Please login to merge, or discard this patch.
apps/dav/lib/Files/FilesHome.php 1 patch
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -33,33 +33,33 @@
 block discarded – undo
33 33
 
34 34
 class FilesHome extends Directory {
35 35
 
36
-	/**
37
-	 * @var array
38
-	 */
39
-	private $principalInfo;
36
+    /**
37
+     * @var array
38
+     */
39
+    private $principalInfo;
40 40
 
41
-	/**
42
-	 * FilesHome constructor.
43
-	 *
44
-	 * @param array $principalInfo
45
-	 * @param FileInfo $userFolder
46
-	 */
47
-	public function __construct($principalInfo, FileInfo $userFolder) {
48
-		$this->principalInfo = $principalInfo;
49
-		$view = \OC\Files\Filesystem::getView();
50
-		parent::__construct($view, $userFolder);
51
-	}
41
+    /**
42
+     * FilesHome constructor.
43
+     *
44
+     * @param array $principalInfo
45
+     * @param FileInfo $userFolder
46
+     */
47
+    public function __construct($principalInfo, FileInfo $userFolder) {
48
+        $this->principalInfo = $principalInfo;
49
+        $view = \OC\Files\Filesystem::getView();
50
+        parent::__construct($view, $userFolder);
51
+    }
52 52
 
53
-	public function delete() {
54
-		throw new Forbidden('Permission denied to delete home folder');
55
-	}
53
+    public function delete() {
54
+        throw new Forbidden('Permission denied to delete home folder');
55
+    }
56 56
 
57
-	public function getName() {
58
-		[,$name] = \Sabre\Uri\split($this->principalInfo['uri']);
59
-		return $name;
60
-	}
57
+    public function getName() {
58
+        [,$name] = \Sabre\Uri\split($this->principalInfo['uri']);
59
+        return $name;
60
+    }
61 61
 
62
-	public function setName($name) {
63
-		throw new Forbidden('Permission denied to rename this folder');
64
-	}
62
+    public function setName($name) {
63
+        throw new Forbidden('Permission denied to rename this folder');
64
+    }
65 65
 }
Please login to merge, or discard this patch.