Completed
Pull Request — master (#32)
by Blizzz
09:50
created

Google::isGoogleDocFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 2
c 1
b 1
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
/**
3
 * @author Adam Williamson <[email protected]>
4
 * @author Arthur Schiwon <[email protected]>
5
 * @author Bart Visscher <[email protected]>
6
 * @author Christopher Schäpers <[email protected]>
7
 * @author Francesco Rovelli <[email protected]>
8
 * @author Jörn Friedrich Dreyer <[email protected]>
9
 * @author Lukas Reschke <[email protected]>
10
 * @author Michael Gapczynski <[email protected]>
11
 * @author Morris Jobke <[email protected]>
12
 * @author Philipp Kapfer <[email protected]>
13
 * @author Robin Appelman <[email protected]>
14
 * @author Robin McCorkell <[email protected]>
15
 * @author Thomas Müller <[email protected]>
16
 * @author Vincent Petry <[email protected]>
17
 *
18
 * @copyright Copyright (c) 2016, ownCloud, Inc.
19
 * @license AGPL-3.0
20
 *
21
 * This code is free software: you can redistribute it and/or modify
22
 * it under the terms of the GNU Affero General Public License, version 3,
23
 * as published by the Free Software Foundation.
24
 *
25
 * This program is distributed in the hope that it will be useful,
26
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28
 * GNU Affero General Public License for more details.
29
 *
30
 * You should have received a copy of the GNU Affero General Public License, version 3,
31
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
32
 *
33
 */
34
35
namespace OCA\Files_External\Lib\Storage;
36
37
use GuzzleHttp\Exception\RequestException;
38
use Icewind\Streams\IteratorDirectory;
39
use Icewind\Streams\RetryWrapper;
40
41
set_include_path(get_include_path().PATH_SEPARATOR.
42
	\OC_App::getAppPath('files_external').'/3rdparty/google-api-php-client/src');
43
require_once 'Google/autoload.php';
44
45
class Google extends \OC\Files\Storage\Common {
46
47
	private $client;
48
	private $id;
49
	private $service;
50
	private $driveFiles;
51
52
	private static $tempFiles = array();
53
54
	// Google Doc mimetypes
55
	const FOLDER = 'application/vnd.google-apps.folder';
56
	const DOCUMENT = 'application/vnd.google-apps.document';
57
	const SPREADSHEET = 'application/vnd.google-apps.spreadsheet';
58
	const DRAWING = 'application/vnd.google-apps.drawing';
59
	const PRESENTATION = 'application/vnd.google-apps.presentation';
60
	const MAP = 'application/vnd.google-apps.map';
61
62
	public function __construct($params) {
63
		if (isset($params['configured']) && $params['configured'] === 'true'
64
			&& isset($params['client_id']) && isset($params['client_secret'])
65
			&& isset($params['token'])
66
		) {
67
			$this->client = new \Google_Client();
68
			$this->client->setClientId($params['client_id']);
69
			$this->client->setClientSecret($params['client_secret']);
70
			$this->client->setScopes(array('https://www.googleapis.com/auth/drive'));
71
			$this->client->setAccessToken($params['token']);
72
			// if curl isn't available we're likely to run into
73
			// https://github.com/google/google-api-php-client/issues/59
74
			// - disable gzip to avoid it.
75
			if (!function_exists('curl_version') || !function_exists('curl_exec')) {
76
				$this->client->setClassConfig("Google_Http_Request", "disable_gzip", true);
77
			}
78
			// note: API connection is lazy
79
			$this->service = new \Google_Service_Drive($this->client);
80
			$token = json_decode($params['token'], true);
81
			$this->id = 'google::'.substr($params['client_id'], 0, 30).$token['created'];
82
		} else {
83
			throw new \Exception('Creating Google storage failed');
84
		}
85
	}
86
87
	public function getId() {
88
		return $this->id;
89
	}
90
91
	/**
92
	 * Get the Google_Service_Drive_DriveFile object for the specified path.
93
	 * Returns false on failure.
94
	 * @param string $path
95
	 * @return \Google_Service_Drive_DriveFile|false
96
	 */
97
	private function getDriveFile($path) {
98
		// Remove leading and trailing slashes
99
		$path = trim($path, '/');
100
		if (isset($this->driveFiles[$path])) {
101
			return $this->driveFiles[$path];
102
		} else if ($path === '') {
103
			$root = $this->service->files->get('root');
104
			$this->driveFiles[$path] = $root;
105
			return $root;
106
		} else {
107
			// Google Drive SDK does not have methods for retrieving files by path
108
			// Instead we must find the id of the parent folder of the file
109
			$parentId = $this->getDriveFile('')->getId();
110
			$folderNames = explode('/', $path);
111
			$path = '';
112
			// Loop through each folder of this path to get to the file
113
			foreach ($folderNames as $name) {
114
				// Reconstruct path from beginning
115
				if ($path === '') {
116
					$path .= $name;
117
				} else {
118
					$path .= '/'.$name;
119
				}
120
				if (isset($this->driveFiles[$path])) {
121
					$parentId = $this->driveFiles[$path]->getId();
122
				} else {
123
					$q = "title='" . str_replace("'","\\'", $name) . "' and '" . str_replace("'","\\'", $parentId) . "' in parents and trashed = false";
124
					$result = $this->service->files->listFiles(array('q' => $q))->getItems();
125
					if (!empty($result)) {
126
						// Google Drive allows files with the same name, ownCloud doesn't
127
						if (count($result) > 1) {
128
							$this->onDuplicateFileDetected($path);
129
							return false;
130
						} else {
131
							$file = current($result);
132
							$this->driveFiles[$path] = $file;
133
							$parentId = $file->getId();
134
						}
135
					} else {
136
						// Google Docs have no extension in their title, so try without extension
137
						$pos = strrpos($path, '.');
138
						if ($pos !== false) {
139
							$pathWithoutExt = substr($path, 0, $pos);
140
							$file = $this->getDriveFile($pathWithoutExt);
141
							if ($file) {
142
								// Switch cached Google_Service_Drive_DriveFile to the correct index
143
								unset($this->driveFiles[$pathWithoutExt]);
144
								$this->driveFiles[$path] = $file;
145
								$parentId = $file->getId();
146
							} else {
147
								return false;
148
							}
149
						} else {
150
							return false;
151
						}
152
					}
153
				}
154
			}
155
			return $this->driveFiles[$path];
156
		}
157
	}
158
159
	/**
160
	 * Set the Google_Service_Drive_DriveFile object in the cache
161
	 * @param string $path
162
	 * @param \Google_Service_Drive_DriveFile|false $file
163
	 */
164
	private function setDriveFile($path, $file) {
165
		$path = trim($path, '/');
166
		$this->driveFiles[$path] = $file;
167
		if ($file === false) {
168
			// Set all child paths as false
169
			$len = strlen($path);
170
			foreach ($this->driveFiles as $key => $file) {
171
				if (substr($key, 0, $len) === $path) {
172
					$this->driveFiles[$key] = false;
173
				}
174
			}
175
		}
176
	}
177
178
	/**
179
	 * Write a log message to inform about duplicate file names
180
	 * @param string $path
181
	 */
182
	private function onDuplicateFileDetected($path) {
183
		$about = $this->service->about->get();
184
		$user = $about->getName();
185
		\OCP\Util::writeLog('files_external',
186
			'Ignoring duplicate file name: '.$path.' on Google Drive for Google user: '.$user,
187
			\OCP\Util::INFO
188
		);
189
	}
190
191
	/**
192
	 * Generate file extension for a Google Doc, choosing Open Document formats for download
193
	 * @param string $mimetype
194
	 * @return string
195
	 */
196
	private function getGoogleDocExtension($mimetype) {
197 View Code Duplication
		if ($mimetype === self::DOCUMENT) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
198
			return 'odt';
199
		} else if ($mimetype === self::SPREADSHEET) {
200
			return 'ods';
201
		} else if ($mimetype === self::DRAWING) {
202
			return 'jpg';
203
		} else if ($mimetype === self::PRESENTATION) {
204
			// Download as .odp is not available
205
			return 'pdf';
206
		} else {
207
			return '';
208
		}
209
	}
210
211
	public function mkdir($path) {
212
		if (!$this->is_dir($path)) {
213
			$parentFolder = $this->getDriveFile(dirname($path));
214
			if ($parentFolder) {
215
				$folder = new \Google_Service_Drive_DriveFile();
216
				$folder->setTitle(basename($path));
217
				$folder->setMimeType(self::FOLDER);
218
				$parent = new \Google_Service_Drive_ParentReference();
219
				$parent->setId($parentFolder->getId());
220
				$folder->setParents(array($parent));
221
				$result = $this->service->files->insert($folder);
222
				if ($result) {
223
					$this->setDriveFile($path, $result);
224
				}
225
				return (bool)$result;
226
			}
227
		}
228
		return false;
229
	}
230
231
	public function rmdir($path) {
232
		if (!$this->isDeletable($path)) {
233
			return false;
234
		}
235
		if (trim($path, '/') === '') {
236
			$dir = $this->opendir($path);
237
			if(is_resource($dir)) {
238
				while (($file = readdir($dir)) !== false) {
239
					if (!\OC\Files\Filesystem::isIgnoredDir($file)) {
240
						if (!$this->unlink($path.'/'.$file)) {
241
							return false;
242
						}
243
					}
244
				}
245
				closedir($dir);
246
			}
247
			$this->driveFiles = array();
248
			return true;
249
		} else {
250
			return $this->unlink($path);
251
		}
252
	}
253
254
	public function opendir($path) {
255
		$folder = $this->getDriveFile($path);
256
		if ($folder) {
257
			$files = array();
258
			$duplicates = array();
259
			$pageToken = true;
260
			while ($pageToken) {
261
				$params = array();
262
				if ($pageToken !== true) {
263
					$params['pageToken'] = $pageToken;
264
				}
265
				$params['q'] = "'" . str_replace("'","\\'", $folder->getId()) . "' in parents and trashed = false";
266
				$children = $this->service->files->listFiles($params);
267
				foreach ($children->getItems() as $child) {
268
					$name = $child->getTitle();
269
					// Check if this is a Google Doc i.e. no extension in name
270
					$extension = $child->getFileExtension();
271
					if (empty($extension)) {
272
						if ($child->getMimeType() === self::MAP) {
273
							continue; // No method known to transfer map files, ignore it
274
						} else if ($child->getMimeType() !== self::FOLDER) {
275
							$name .= '.'.$this->getGoogleDocExtension($child->getMimeType());
276
						}
277
					}
278
					if ($path === '') {
279
						$filepath = $name;
280
					} else {
281
						$filepath = $path.'/'.$name;
282
					}
283
					// Google Drive allows files with the same name, ownCloud doesn't
284
					// Prevent opendir() from returning any duplicate files
285
					$key = array_search($name, $files);
286
					if ($key !== false || isset($duplicates[$filepath])) {
287
						if (!isset($duplicates[$filepath])) {
288
							$duplicates[$filepath] = true;
289
							$this->setDriveFile($filepath, false);
290
							unset($files[$key]);
291
							$this->onDuplicateFileDetected($filepath);
292
						}
293
					} else {
294
						// Cache the Google_Service_Drive_DriveFile for future use
295
						$this->setDriveFile($filepath, $child);
296
						$files[] = $name;
297
					}
298
				}
299
				$pageToken = $children->getNextPageToken();
300
			}
301
			return IteratorDirectory::wrap($files);
302
		} else {
303
			return false;
304
		}
305
	}
306
307
	public function stat($path) {
308
		$file = $this->getDriveFile($path);
309
		if ($file) {
310
			$stat = array();
311
			if ($this->filetype($path) === 'dir') {
312
				$stat['size'] = 0;
313
			} else {
314
				// Check if this is a Google Doc
315
				if ($this->getMimeType($path) !== $file->getMimeType()) {
316
					// Return unknown file size
317
					$stat['size'] = \OCP\Files\FileInfo::SPACE_UNKNOWN;
318
				} else {
319
					$stat['size'] = $file->getFileSize();
320
				}
321
			}
322
			$stat['atime'] = strtotime($file->getLastViewedByMeDate());
323
			$stat['mtime'] = strtotime($file->getModifiedDate());
324
			$stat['ctime'] = strtotime($file->getCreatedDate());
325
			return $stat;
326
		} else {
327
			return false;
328
		}
329
	}
330
331
	public function filetype($path) {
332
		if ($path === '') {
333
			return 'dir';
334
		} else {
335
			$file = $this->getDriveFile($path);
336
			if ($file) {
337
				if ($file->getMimeType() === self::FOLDER) {
338
					return 'dir';
339
				} else {
340
					return 'file';
341
				}
342
			} else {
343
				return false;
344
			}
345
		}
346
	}
347
348
	public function isUpdatable($path) {
349
		$file = $this->getDriveFile($path);
350
		if ($file) {
351
			return $file->getEditable();
352
		} else {
353
			return false;
354
		}
355
	}
356
357
	public function file_exists($path) {
358
		return (bool)$this->getDriveFile($path);
359
	}
360
361
	public function unlink($path) {
362
		$file = $this->getDriveFile($path);
363
		if ($file) {
364
			$result = $this->service->files->trash($file->getId());
365
			if ($result) {
366
				$this->setDriveFile($path, false);
367
			}
368
			return (bool)$result;
369
		} else {
370
			return false;
371
		}
372
	}
373
374
	public function rename($path1, $path2) {
375
		$file = $this->getDriveFile($path1);
376
		if ($file) {
377
			$newFile = $this->getDriveFile($path2);
378
			if (dirname($path1) === dirname($path2)) {
379
				if ($newFile) {
380
					// rename to the name of the target file, could be an office file without extension
381
					$file->setTitle($newFile->getTitle());
382
				} else {
383
					$file->setTitle(basename(($path2)));
384
				}
385
			} else {
386
				// Change file parent
387
				$parentFolder2 = $this->getDriveFile(dirname($path2));
388
				if ($parentFolder2) {
389
					$parent = new \Google_Service_Drive_ParentReference();
390
					$parent->setId($parentFolder2->getId());
391
					$file->setParents(array($parent));
392
				} else {
393
					return false;
394
				}
395
			}
396
			// We need to get the object for the existing file with the same
397
			// name (if there is one) before we do the patch. If oldfile
398
			// exists and is a directory we have to delete it before we
399
			// do the rename too.
400
			$oldfile = $this->getDriveFile($path2);
401
			if ($oldfile && $this->is_dir($path2)) {
402
				$this->rmdir($path2);
403
				$oldfile = false;
404
			}
405
			$result = $this->service->files->patch($file->getId(), $file);
406
			if ($result) {
407
				$this->setDriveFile($path1, false);
408
				$this->setDriveFile($path2, $result);
409
				if ($oldfile && $newFile) {
410
					// only delete if they have a different id (same id can happen for part files)
411
					if ($newFile->getId() !== $oldfile->getId()) {
412
						$this->service->files->delete($oldfile->getId());
413
					}
414
				}
415
			}
416
			return (bool)$result;
417
		} else {
418
			return false;
419
		}
420
	}
421
422
	public function fopen($path, $mode) {
423
		$pos = strrpos($path, '.');
424
		if ($pos !== false) {
425
			$ext = substr($path, $pos);
426
		} else {
427
			$ext = '';
428
		}
429
		switch ($mode) {
430
			case 'r':
431
			case 'rb':
432
				$file = $this->getDriveFile($path);
433
				if ($file) {
434
					$exportLinks = $file->getExportLinks();
435
					$mimetype = $this->getMimeType($path);
436
					$downloadUrl = null;
0 ignored issues
show
Unused Code introduced by
$downloadUrl is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
437
					if ($exportLinks && isset($exportLinks[$mimetype])) {
438
						$downloadUrl = $exportLinks[$mimetype];
439
					} else {
440
						$downloadUrl = $file->getDownloadUrl();
441
					}
442
					if (isset($downloadUrl)) {
443
						$request = new \Google_Http_Request($downloadUrl, 'GET', null, null);
444
						$httpRequest = $this->client->getAuth()->sign($request);
445
						// the library's service doesn't support streaming, so we use Guzzle instead
446
						$client = \OC::$server->getHTTPClientService()->newClient();
447
						try {
448
							$response = $client->get($downloadUrl, [
449
								'headers' => $httpRequest->getRequestHeaders(),
450
								'stream' => true,
451
								'verify' => realpath(__DIR__ . '/../../../3rdparty/google-api-php-client/src/Google/IO/cacerts.pem'),
452
							]);
453
						} catch (RequestException $e) {
0 ignored issues
show
Bug introduced by
The class GuzzleHttp\Exception\RequestException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
454 View Code Duplication
							if(!is_null($e->getResponse())) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
455
								if ($e->getResponse()->getStatusCode() === 404) {
456
									return false;
457
								} else {
458
									throw $e;
459
								}
460
							} else {
461
								throw $e;
462
							}
463
						}
464
465
						$handle = $response->getBody();
466
						return RetryWrapper::wrap($handle);
467
					}
468
				}
469
				return false;
470
			case 'w':
471
			case 'wb':
472
			case 'a':
473
			case 'ab':
474
			case 'r+':
475
			case 'w+':
476
			case 'wb+':
477
			case 'a+':
478
			case 'x':
479
			case 'x+':
480
			case 'c':
481
			case 'c+':
482
				$tmpFile = \OCP\Files::tmpFile($ext);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\Files::tmpFile() has been deprecated with message: 8.1.0 use getTemporaryFile() of \OCP\ITempManager - \OC::$server->getTempManager()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
483
				\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
484
				if ($this->file_exists($path)) {
485
					$source = $this->fopen($path, 'rb');
486
					file_put_contents($tmpFile, $source);
487
				}
488
				self::$tempFiles[$tmpFile] = $path;
489
				return fopen('close://'.$tmpFile, $mode);
490
		}
491
	}
492
493
	public function writeBack($tmpFile) {
494
		if (isset(self::$tempFiles[$tmpFile])) {
495
			$path = self::$tempFiles[$tmpFile];
496
			$parentFolder = $this->getDriveFile(dirname($path));
497
			if ($parentFolder) {
498
				$mimetype = \OC::$server->getMimeTypeDetector()->detect($tmpFile);
499
				$params = array(
500
					'mimeType' => $mimetype,
501
					'uploadType' => 'media'
502
				);
503
				$result = false;
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
504
505
				$chunkSizeBytes = 10 * 1024 * 1024;
506
507
				$useChunking = false;
508
				$size = filesize($tmpFile);
509
				if ($size > $chunkSizeBytes) {
510
					$useChunking = true;
511
				} else {
512
					$params['data'] = file_get_contents($tmpFile);
513
				}
514
515
				if ($this->file_exists($path)) {
516
					$file = $this->getDriveFile($path);
517
					$this->client->setDefer($useChunking);
518
					$request = $this->service->files->update($file->getId(), $file, $params);
519 View Code Duplication
				} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
520
					$file = new \Google_Service_Drive_DriveFile();
521
					$file->setTitle(basename($path));
522
					$file->setMimeType($mimetype);
523
					$parent = new \Google_Service_Drive_ParentReference();
524
					$parent->setId($parentFolder->getId());
525
					$file->setParents(array($parent));
526
					$this->client->setDefer($useChunking);
527
					$request = $this->service->files->insert($file, $params);
528
				}
529
530
				if ($useChunking) {
531
					// Create a media file upload to represent our upload process.
532
					$media = new \Google_Http_MediaFileUpload(
533
						$this->client,
534
						$request,
535
						'text/plain',
536
						null,
537
						true,
538
						$chunkSizeBytes
539
					);
540
					$media->setFileSize($size);
541
542
					// Upload the various chunks. $status will be false until the process is
543
					// complete.
544
					$status = false;
545
					$handle = fopen($tmpFile, 'rb');
546
					while (!$status && !feof($handle)) {
547
						$chunk = fread($handle, $chunkSizeBytes);
548
						$status = $media->nextChunk($chunk);
549
					}
550
551
					// The final value of $status will be the data from the API for the object
552
					// that has been uploaded.
553
					$result = false;
554
					if ($status !== false) {
555
						$result = $status;
556
					}
557
558
					fclose($handle);
559
				} else {
560
					$result = $request;
561
				}
562
563
				// Reset to the client to execute requests immediately in the future.
564
				$this->client->setDefer(false);
565
566
				if ($result) {
567
					$this->setDriveFile($path, $result);
568
				}
569
			}
570
			unlink($tmpFile);
571
		}
572
	}
573
574
	public function getMimeType($path) {
575
		$file = $this->getDriveFile($path);
576
		if ($file) {
577
			$mimetype = $file->getMimeType();
578
			// Convert Google Doc mimetypes, choosing Open Document formats for download
579
			if ($mimetype === self::FOLDER) {
580
				return 'httpd/unix-directory';
581 View Code Duplication
			} else if ($mimetype === self::DOCUMENT) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
582
				return 'application/vnd.oasis.opendocument.text';
583
			} else if ($mimetype === self::SPREADSHEET) {
584
				return 'application/x-vnd.oasis.opendocument.spreadsheet';
585
			} else if ($mimetype === self::DRAWING) {
586
				return 'image/jpeg';
587
			} else if ($mimetype === self::PRESENTATION) {
588
				// Download as .odp is not available
589
				return 'application/pdf';
590
			} else {
591
				// use extension-based detection, could be an encrypted file
592
				return parent::getMimeType($path);
593
			}
594
		} else {
595
			return false;
596
		}
597
	}
598
599
	public function free_space($path) {
600
		$about = $this->service->about->get();
601
		return $about->getQuotaBytesTotal() - $about->getQuotaBytesUsed();
0 ignored issues
show
Bug Compatibility introduced by
The expression $about->getQuotaBytesTot...t->getQuotaBytesUsed(); of type integer|double adds the type double to the return on line 601 which is incompatible with the return type declared by the interface OCP\Files\Storage::free_space of type integer|false.
Loading history...
602
	}
603
604
	public function touch($path, $mtime = null) {
605
		$file = $this->getDriveFile($path);
606
		$result = false;
607
		if ($file) {
608
			if (isset($mtime)) {
609
				// This is just RFC3339, but frustratingly, GDrive's API *requires*
610
				// the fractions portion be present, while no handy PHP constant
611
				// for RFC3339 or ISO8601 includes it. So we do it ourselves.
612
				$file->setModifiedDate(date('Y-m-d\TH:i:s.uP', $mtime));
613
				$result = $this->service->files->patch($file->getId(), $file, array(
614
					'setModifiedDate' => true,
615
				));
616
			} else {
617
				$result = $this->service->files->touch($file->getId());
618
			}
619 View Code Duplication
		} else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
620
			$parentFolder = $this->getDriveFile(dirname($path));
621
			if ($parentFolder) {
622
				$file = new \Google_Service_Drive_DriveFile();
623
				$file->setTitle(basename($path));
624
				$parent = new \Google_Service_Drive_ParentReference();
625
				$parent->setId($parentFolder->getId());
626
				$file->setParents(array($parent));
627
				$result = $this->service->files->insert($file);
628
			}
629
		}
630
		if ($result) {
631
			$this->setDriveFile($path, $result);
632
		}
633
		return (bool)$result;
634
	}
635
636
	public function test() {
637
		if ($this->free_space('')) {
638
			return true;
639
		}
640
		return false;
641
	}
642
643
	public function hasUpdated($path, $time) {
644
		$appConfig = \OC::$server->getAppConfig();
645
		if ($this->is_file($path)) {
646
			return parent::hasUpdated($path, $time);
647
		} else {
648
			// Google Drive doesn't change modified times of folders when files inside are updated
649
			// Instead we use the Changes API to see if folders have been updated, and it's a pain
650
			$folder = $this->getDriveFile($path);
651
			if ($folder) {
652
				$result = false;
653
				$folderId = $folder->getId();
654
				$startChangeId = $appConfig->getValue('files_external', $this->getId().'cId');
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::getValue() has been deprecated with message: 8.0.0 use method getAppValue of \OCP\IConfig This function gets a value from the appconfig table. If the key does
not exist the default value will be returned

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
655
				$params = array(
656
					'includeDeleted' => true,
657
					'includeSubscribed' => true,
658
				);
659
				if (isset($startChangeId)) {
660
					$startChangeId = (int)$startChangeId;
661
					$largestChangeId = $startChangeId;
662
					$params['startChangeId'] = $startChangeId + 1;
663
				} else {
664
					$largestChangeId = 0;
665
				}
666
				$pageToken = true;
667
				while ($pageToken) {
668
					if ($pageToken !== true) {
669
						$params['pageToken'] = $pageToken;
670
					}
671
					$changes = $this->service->changes->listChanges($params);
672
					if ($largestChangeId === 0 || $largestChangeId === $startChangeId) {
673
						$largestChangeId = $changes->getLargestChangeId();
674
					}
675
					if (isset($startChangeId)) {
676
						// Check if a file in this folder has been updated
677
						// There is no way to filter by folder at the API level...
678
						foreach ($changes->getItems() as $change) {
679
							$file = $change->getFile();
680
							if ($file) {
681
								foreach ($file->getParents() as $parent) {
682
									if ($parent->getId() === $folderId) {
683
										$result = true;
684
									// Check if there are changes in different folders
685
									} else if ($change->getId() <= $largestChangeId) {
686
										// Decrement id so this change is fetched when called again
687
										$largestChangeId = $change->getId();
688
										$largestChangeId--;
689
									}
690
								}
691
							}
692
						}
693
						$pageToken = $changes->getNextPageToken();
694
					} else {
695
						// Assuming the initial scan just occurred and changes are negligible
696
						break;
697
					}
698
				}
699
				$appConfig->setValue('files_external', $this->getId().'cId', $largestChangeId);
0 ignored issues
show
Deprecated Code introduced by
The method OCP\IAppConfig::setValue() has been deprecated with message: 8.0.0 use method setAppValue of \OCP\IConfig Sets a value. If the key did not exist before it will be created.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
700
				return $result;
701
			}
702
		}
703
		return false;
704
	}
705
706
	/**
707
	 * check if curl is installed
708
	 */
709
	public static function checkDependencies() {
710
		return true;
711
	}
712
713
}
714