Passed
Push — master ( 0f6e7a...e7b308 )
by Roeland
11:54 queued 10s
created
lib/private/DirectEditing/Manager.php 1 patch
Indentation   +228 added lines, -228 removed lines patch added patch discarded remove patch
@@ -51,233 +51,233 @@
 block discarded – undo
51 51
 
52 52
 class Manager implements IManager {
53 53
 
54
-	private const TOKEN_CLEANUP_TIME = 12 * 60 * 60 ;
55
-
56
-	public const TABLE_TOKENS = 'direct_edit';
57
-
58
-	/** @var IEditor[] */
59
-	private $editors = [];
60
-
61
-	/** @var IDBConnection */
62
-	private $connection;
63
-	/**
64
-	 * @var ISecureRandom
65
-	 */
66
-	private $random;
67
-	private $userId;
68
-	private $rootFolder;
69
-	/** @var IL10N */
70
-	private $l10n;
71
-
72
-	public function __construct(
73
-		ISecureRandom $random,
74
-		IDBConnection $connection,
75
-		IUserSession $userSession,
76
-		IRootFolder $rootFolder,
77
-		IFactory $l10nFactory
78
-	) {
79
-		$this->random = $random;
80
-		$this->connection = $connection;
81
-		$this->userId = $userSession->getUser() ? $userSession->getUser()->getUID() : null;
82
-		$this->rootFolder = $rootFolder;
83
-		$this->l10n = $l10nFactory->get('core');
84
-	}
85
-
86
-	public function registerDirectEditor(IEditor $directEditor): void {
87
-		$this->editors[$directEditor->getId()] = $directEditor;
88
-	}
89
-
90
-	public function getEditors(): array {
91
-		return $this->editors;
92
-	}
93
-
94
-	public function getTemplates(string $editor, string $type): array {
95
-		if (!array_key_exists($editor, $this->editors)) {
96
-			throw new \RuntimeException('No matching editor found');
97
-		}
98
-		$templates = [];
99
-		foreach ($this->editors[$editor]->getCreators() as $creator) {
100
-			if ($creator->getId() === $type) {
101
-				$templates = [
102
-					'empty' => [
103
-						'id' => 'empty',
104
-						'title' => $this->l10n->t('Empty file'),
105
-						'preview' => null
106
-					]
107
-				];
108
-
109
-				if ($creator instanceof ACreateFromTemplate) {
110
-					$templates = $creator->getTemplates();
111
-				}
112
-
113
-				$templates = array_map(function ($template) use ($creator) {
114
-					$template['extension'] = $creator->getExtension();
115
-					$template['mimetype'] = $creator->getMimetype();
116
-					return $template;
117
-				}, $templates);
118
-			}
119
-		}
120
-		$return = [];
121
-		$return['templates'] =  $templates;
122
-		return $return;
123
-	}
124
-
125
-	public function create(string $path, string $editorId, string $creatorId, $templateId = null): string {
126
-		$userFolder = $this->rootFolder->getUserFolder($this->userId);
127
-		try {
128
-			$file = $userFolder->get($path);
129
-			throw new \RuntimeException('File already exists');
130
-		} catch (\OCP\Files\NotFoundException $e) {
131
-			$file = $userFolder->newFile($path);
132
-			$editor = $this->getEditor($editorId);
133
-			$creators = $editor->getCreators();
134
-			foreach ($creators as $creator) {
135
-				if ($creator->getId() === $creatorId) {
136
-					$creator->create($file, $creatorId, $templateId);
137
-					return $this->createToken($editorId, $file, $path);
138
-				}
139
-			}
140
-		}
141
-
142
-		throw new \RuntimeException('No creator found');
143
-	}
144
-
145
-	public function open(string $filePath, string $editorId = null): string {
146
-		/** @var File $file */
147
-		$file = $this->rootFolder->getUserFolder($this->userId)->get($filePath);
148
-
149
-		if ($editorId === null) {
150
-			$editorId = $this->findEditorForFile($file);
151
-		}
152
-		if (!array_key_exists($editorId, $this->editors)) {
153
-			throw new \RuntimeException("Editor $editorId is unknown");
154
-		}
155
-
156
-		return $this->createToken($editorId, $file, $filePath);
157
-	}
158
-
159
-	private function findEditorForFile(File $file) {
160
-		foreach ($this->editors as $editor) {
161
-			if (in_array($file->getMimeType(), $editor->getMimetypes())) {
162
-				return $editor->getId();
163
-			}
164
-		}
165
-		throw new \RuntimeException('No default editor found for files mimetype');
166
-	}
167
-
168
-	public function edit(string $token): Response {
169
-		try {
170
-			/** @var IEditor $editor */
171
-			$tokenObject = $this->getToken($token);
172
-			if ($tokenObject->hasBeenAccessed()) {
173
-				throw new \RuntimeException('Token has already been used and can only be used for followup requests');
174
-			}
175
-			$editor = $this->getEditor($tokenObject->getEditor());
176
-			$this->accessToken($token);
177
-
178
-		} catch (\Throwable $throwable) {
179
-			$this->invalidateToken($token);
180
-			return new NotFoundResponse();
181
-		}
182
-		return $editor->open($tokenObject);
183
-	}
184
-
185
-	public function editSecure(File $file, string $editorId): TemplateResponse {
186
-		// TODO: Implementation in follow up
187
-	}
188
-
189
-	private function getEditor($editorId): IEditor {
190
-		if (!array_key_exists($editorId, $this->editors)) {
191
-			throw new \RuntimeException('No editor found');
192
-		}
193
-		return $this->editors[$editorId];
194
-	}
195
-
196
-	public function getToken(string $token): IToken {
197
-		$query = $this->connection->getQueryBuilder();
198
-		$query->select('*')->from(self::TABLE_TOKENS)
199
-			->where($query->expr()->eq('token', $query->createNamedParameter($token, IQueryBuilder::PARAM_STR)));
200
-		$result = $query->execute();
201
-		if ($tokenRow = $result->fetch(FetchMode::ASSOCIATIVE)) {
202
-			return new Token($this, $tokenRow);
203
-		}
204
-		throw new \RuntimeException('Failed to validate the token');
205
-	}
206
-
207
-	public function cleanup(): int {
208
-		$query = $this->connection->getQueryBuilder();
209
-		$query->delete(self::TABLE_TOKENS)
210
-			->where($query->expr()->lt('timestamp', $query->createNamedParameter(time() - self::TOKEN_CLEANUP_TIME)));
211
-		return $query->execute();
212
-	}
213
-
214
-	public function refreshToken(string $token): bool {
215
-		$query = $this->connection->getQueryBuilder();
216
-		$query->update(self::TABLE_TOKENS)
217
-			->set('timestamp', $query->createNamedParameter(time(), IQueryBuilder::PARAM_INT))
218
-			->where($query->expr()->eq('token', $query->createNamedParameter($token, IQueryBuilder::PARAM_STR)));
219
-		$result = $query->execute();
220
-		return $result !== 0;
221
-	}
222
-
223
-
224
-	public function invalidateToken(string $token): bool {
225
-		$query = $this->connection->getQueryBuilder();
226
-		$query->delete(self::TABLE_TOKENS)
227
-			->where($query->expr()->eq('token', $query->createNamedParameter($token, IQueryBuilder::PARAM_STR)));
228
-		$result = $query->execute();
229
-		return $result !== 0;
230
-	}
231
-
232
-	public function accessToken(string $token): bool {
233
-		$query = $this->connection->getQueryBuilder();
234
-		$query->update(self::TABLE_TOKENS)
235
-			->set('accessed', $query->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
236
-			->set('timestamp', $query->createNamedParameter(time(), IQueryBuilder::PARAM_INT))
237
-			->where($query->expr()->eq('token', $query->createNamedParameter($token, IQueryBuilder::PARAM_STR)));
238
-		$result = $query->execute();
239
-		return $result !== 0;
240
-	}
241
-
242
-	public function invokeTokenScope($userId): void {
243
-		\OC_User::setIncognitoMode(true);
244
-		\OC_User::setUserId($userId);
245
-	}
246
-
247
-	public function createToken($editorId, File $file, string $filePath, IShare $share = null): string {
248
-		$token = $this->random->generate(64, ISecureRandom::CHAR_HUMAN_READABLE);
249
-		$query = $this->connection->getQueryBuilder();
250
-		$query->insert(self::TABLE_TOKENS)
251
-			->values([
252
-				'token' => $query->createNamedParameter($token),
253
-				'editor_id' => $query->createNamedParameter($editorId),
254
-				'file_id' => $query->createNamedParameter($file->getId()),
255
-				'file_path' => $query->createNamedParameter($filePath),
256
-				'user_id' => $query->createNamedParameter($this->userId),
257
-				'share_id' => $query->createNamedParameter($share !== null ? $share->getId(): null),
258
-				'timestamp' => $query->createNamedParameter(time())
259
-			]);
260
-		$query->execute();
261
-		return $token;
262
-	}
263
-
264
-	/**
265
-	 * @param $userId
266
-	 * @param $fileId
267
-	 * @param null $filePath
268
-	 * @return Node
269
-	 * @throws NotFoundException
270
-	 */
271
-	public function getFileForToken($userId, $fileId, $filePath = null): Node {
272
-		$userFolder = $this->rootFolder->getUserFolder($userId);
273
-		if ($filePath !== null) {
274
-			return $userFolder->get($filePath);
275
-		}
276
-		$files = $userFolder->getById($fileId);
277
-		if (count($files) === 0) {
278
-			throw new NotFoundException('File nound found by id ' . $fileId);
279
-		}
280
-		return $files[0];
281
-	}
54
+    private const TOKEN_CLEANUP_TIME = 12 * 60 * 60 ;
55
+
56
+    public const TABLE_TOKENS = 'direct_edit';
57
+
58
+    /** @var IEditor[] */
59
+    private $editors = [];
60
+
61
+    /** @var IDBConnection */
62
+    private $connection;
63
+    /**
64
+     * @var ISecureRandom
65
+     */
66
+    private $random;
67
+    private $userId;
68
+    private $rootFolder;
69
+    /** @var IL10N */
70
+    private $l10n;
71
+
72
+    public function __construct(
73
+        ISecureRandom $random,
74
+        IDBConnection $connection,
75
+        IUserSession $userSession,
76
+        IRootFolder $rootFolder,
77
+        IFactory $l10nFactory
78
+    ) {
79
+        $this->random = $random;
80
+        $this->connection = $connection;
81
+        $this->userId = $userSession->getUser() ? $userSession->getUser()->getUID() : null;
82
+        $this->rootFolder = $rootFolder;
83
+        $this->l10n = $l10nFactory->get('core');
84
+    }
85
+
86
+    public function registerDirectEditor(IEditor $directEditor): void {
87
+        $this->editors[$directEditor->getId()] = $directEditor;
88
+    }
89
+
90
+    public function getEditors(): array {
91
+        return $this->editors;
92
+    }
93
+
94
+    public function getTemplates(string $editor, string $type): array {
95
+        if (!array_key_exists($editor, $this->editors)) {
96
+            throw new \RuntimeException('No matching editor found');
97
+        }
98
+        $templates = [];
99
+        foreach ($this->editors[$editor]->getCreators() as $creator) {
100
+            if ($creator->getId() === $type) {
101
+                $templates = [
102
+                    'empty' => [
103
+                        'id' => 'empty',
104
+                        'title' => $this->l10n->t('Empty file'),
105
+                        'preview' => null
106
+                    ]
107
+                ];
108
+
109
+                if ($creator instanceof ACreateFromTemplate) {
110
+                    $templates = $creator->getTemplates();
111
+                }
112
+
113
+                $templates = array_map(function ($template) use ($creator) {
114
+                    $template['extension'] = $creator->getExtension();
115
+                    $template['mimetype'] = $creator->getMimetype();
116
+                    return $template;
117
+                }, $templates);
118
+            }
119
+        }
120
+        $return = [];
121
+        $return['templates'] =  $templates;
122
+        return $return;
123
+    }
124
+
125
+    public function create(string $path, string $editorId, string $creatorId, $templateId = null): string {
126
+        $userFolder = $this->rootFolder->getUserFolder($this->userId);
127
+        try {
128
+            $file = $userFolder->get($path);
129
+            throw new \RuntimeException('File already exists');
130
+        } catch (\OCP\Files\NotFoundException $e) {
131
+            $file = $userFolder->newFile($path);
132
+            $editor = $this->getEditor($editorId);
133
+            $creators = $editor->getCreators();
134
+            foreach ($creators as $creator) {
135
+                if ($creator->getId() === $creatorId) {
136
+                    $creator->create($file, $creatorId, $templateId);
137
+                    return $this->createToken($editorId, $file, $path);
138
+                }
139
+            }
140
+        }
141
+
142
+        throw new \RuntimeException('No creator found');
143
+    }
144
+
145
+    public function open(string $filePath, string $editorId = null): string {
146
+        /** @var File $file */
147
+        $file = $this->rootFolder->getUserFolder($this->userId)->get($filePath);
148
+
149
+        if ($editorId === null) {
150
+            $editorId = $this->findEditorForFile($file);
151
+        }
152
+        if (!array_key_exists($editorId, $this->editors)) {
153
+            throw new \RuntimeException("Editor $editorId is unknown");
154
+        }
155
+
156
+        return $this->createToken($editorId, $file, $filePath);
157
+    }
158
+
159
+    private function findEditorForFile(File $file) {
160
+        foreach ($this->editors as $editor) {
161
+            if (in_array($file->getMimeType(), $editor->getMimetypes())) {
162
+                return $editor->getId();
163
+            }
164
+        }
165
+        throw new \RuntimeException('No default editor found for files mimetype');
166
+    }
167
+
168
+    public function edit(string $token): Response {
169
+        try {
170
+            /** @var IEditor $editor */
171
+            $tokenObject = $this->getToken($token);
172
+            if ($tokenObject->hasBeenAccessed()) {
173
+                throw new \RuntimeException('Token has already been used and can only be used for followup requests');
174
+            }
175
+            $editor = $this->getEditor($tokenObject->getEditor());
176
+            $this->accessToken($token);
177
+
178
+        } catch (\Throwable $throwable) {
179
+            $this->invalidateToken($token);
180
+            return new NotFoundResponse();
181
+        }
182
+        return $editor->open($tokenObject);
183
+    }
184
+
185
+    public function editSecure(File $file, string $editorId): TemplateResponse {
186
+        // TODO: Implementation in follow up
187
+    }
188
+
189
+    private function getEditor($editorId): IEditor {
190
+        if (!array_key_exists($editorId, $this->editors)) {
191
+            throw new \RuntimeException('No editor found');
192
+        }
193
+        return $this->editors[$editorId];
194
+    }
195
+
196
+    public function getToken(string $token): IToken {
197
+        $query = $this->connection->getQueryBuilder();
198
+        $query->select('*')->from(self::TABLE_TOKENS)
199
+            ->where($query->expr()->eq('token', $query->createNamedParameter($token, IQueryBuilder::PARAM_STR)));
200
+        $result = $query->execute();
201
+        if ($tokenRow = $result->fetch(FetchMode::ASSOCIATIVE)) {
202
+            return new Token($this, $tokenRow);
203
+        }
204
+        throw new \RuntimeException('Failed to validate the token');
205
+    }
206
+
207
+    public function cleanup(): int {
208
+        $query = $this->connection->getQueryBuilder();
209
+        $query->delete(self::TABLE_TOKENS)
210
+            ->where($query->expr()->lt('timestamp', $query->createNamedParameter(time() - self::TOKEN_CLEANUP_TIME)));
211
+        return $query->execute();
212
+    }
213
+
214
+    public function refreshToken(string $token): bool {
215
+        $query = $this->connection->getQueryBuilder();
216
+        $query->update(self::TABLE_TOKENS)
217
+            ->set('timestamp', $query->createNamedParameter(time(), IQueryBuilder::PARAM_INT))
218
+            ->where($query->expr()->eq('token', $query->createNamedParameter($token, IQueryBuilder::PARAM_STR)));
219
+        $result = $query->execute();
220
+        return $result !== 0;
221
+    }
222
+
223
+
224
+    public function invalidateToken(string $token): bool {
225
+        $query = $this->connection->getQueryBuilder();
226
+        $query->delete(self::TABLE_TOKENS)
227
+            ->where($query->expr()->eq('token', $query->createNamedParameter($token, IQueryBuilder::PARAM_STR)));
228
+        $result = $query->execute();
229
+        return $result !== 0;
230
+    }
231
+
232
+    public function accessToken(string $token): bool {
233
+        $query = $this->connection->getQueryBuilder();
234
+        $query->update(self::TABLE_TOKENS)
235
+            ->set('accessed', $query->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
236
+            ->set('timestamp', $query->createNamedParameter(time(), IQueryBuilder::PARAM_INT))
237
+            ->where($query->expr()->eq('token', $query->createNamedParameter($token, IQueryBuilder::PARAM_STR)));
238
+        $result = $query->execute();
239
+        return $result !== 0;
240
+    }
241
+
242
+    public function invokeTokenScope($userId): void {
243
+        \OC_User::setIncognitoMode(true);
244
+        \OC_User::setUserId($userId);
245
+    }
246
+
247
+    public function createToken($editorId, File $file, string $filePath, IShare $share = null): string {
248
+        $token = $this->random->generate(64, ISecureRandom::CHAR_HUMAN_READABLE);
249
+        $query = $this->connection->getQueryBuilder();
250
+        $query->insert(self::TABLE_TOKENS)
251
+            ->values([
252
+                'token' => $query->createNamedParameter($token),
253
+                'editor_id' => $query->createNamedParameter($editorId),
254
+                'file_id' => $query->createNamedParameter($file->getId()),
255
+                'file_path' => $query->createNamedParameter($filePath),
256
+                'user_id' => $query->createNamedParameter($this->userId),
257
+                'share_id' => $query->createNamedParameter($share !== null ? $share->getId(): null),
258
+                'timestamp' => $query->createNamedParameter(time())
259
+            ]);
260
+        $query->execute();
261
+        return $token;
262
+    }
263
+
264
+    /**
265
+     * @param $userId
266
+     * @param $fileId
267
+     * @param null $filePath
268
+     * @return Node
269
+     * @throws NotFoundException
270
+     */
271
+    public function getFileForToken($userId, $fileId, $filePath = null): Node {
272
+        $userFolder = $this->rootFolder->getUserFolder($userId);
273
+        if ($filePath !== null) {
274
+            return $userFolder->get($filePath);
275
+        }
276
+        $files = $userFolder->getById($fileId);
277
+        if (count($files) === 0) {
278
+            throw new NotFoundException('File nound found by id ' . $fileId);
279
+        }
280
+        return $files[0];
281
+    }
282 282
 
283 283
 }
Please login to merge, or discard this patch.