Switch to using Google Drive SDK, closes #2047
This commit is contained in:
parent
1ec92b6377
commit
d8c660c6d5
|
@ -1,64 +1,41 @@
|
|||
<?php
|
||||
|
||||
require_once 'Google/common.inc.php';
|
||||
require_once 'google-api-php-client/src/Google_Client.php';
|
||||
|
||||
OCP\JSON::checkAppEnabled('files_external');
|
||||
OCP\JSON::checkLoggedIn();
|
||||
OCP\JSON::callCheck();
|
||||
|
||||
$consumer = new OAuthConsumer('anonymous', 'anonymous');
|
||||
$sigMethod = new OAuthSignatureMethod_HMAC_SHA1();
|
||||
if (isset($_POST['step'])) {
|
||||
switch ($_POST['step']) {
|
||||
case 1:
|
||||
if (isset($_POST['callback'])) {
|
||||
$callback = $_POST['callback'];
|
||||
} else {
|
||||
$callback = null;
|
||||
}
|
||||
$scope = 'https://docs.google.com/feeds/'
|
||||
.' https://docs.googleusercontent.com/'
|
||||
.' https://spreadsheets.google.com/feeds/';
|
||||
$url = 'https://www.google.com/accounts/OAuthGetRequestToken?scope='.urlencode($scope);
|
||||
$params = array('scope' => $scope, 'oauth_callback' => $callback);
|
||||
$request = OAuthRequest::from_consumer_and_token($consumer, null, 'GET', $url, $params);
|
||||
$request->sign_request($sigMethod, $consumer, null);
|
||||
$response = send_signed_request('GET', $url, array($request->to_header()), null, false);
|
||||
$token = array();
|
||||
parse_str($response, $token);
|
||||
if (isset($token['oauth_token']) && isset($token['oauth_token_secret'])) {
|
||||
$authUrl = 'https://www.google.com/accounts/OAuthAuthorizeToken?oauth_token='.$token['oauth_token'];
|
||||
OCP\JSON::success(array('data' => array('url' => $authUrl,
|
||||
'request_token' => $token['oauth_token'],
|
||||
'request_token_secret' => $token['oauth_token_secret'])));
|
||||
} else {
|
||||
if (isset($_POST['client_id']) && isset($_POST['client_secret']) && isset($_POST['redirect'])) {
|
||||
$client = new Google_Client();
|
||||
$client->setClientId($_POST['client_id']);
|
||||
$client->setClientSecret($_POST['client_secret']);
|
||||
$client->setRedirectUri($_POST['redirect']);
|
||||
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
|
||||
if (isset($_POST['step'])) {
|
||||
$step = $_POST['step'];
|
||||
if ($step == 1) {
|
||||
try {
|
||||
$authUrl = $client->createAuthUrl();
|
||||
OCP\JSON::success(array('data' => array(
|
||||
'url' => $authUrl
|
||||
)));
|
||||
} catch (Exception $exception) {
|
||||
OCP\JSON::error(array('data' => array(
|
||||
'message' => 'Fetching request tokens failed. Error: '.$response
|
||||
)));
|
||||
'message' => 'Step 1 failed. Exception: '.$exception->getMessage()
|
||||
)));
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (isset($_POST['oauth_verifier'])
|
||||
&& isset($_POST['request_token'])
|
||||
&& isset($_POST['request_token_secret'])
|
||||
) {
|
||||
$token = new OAuthToken($_POST['request_token'], $_POST['request_token_secret']);
|
||||
$url = 'https://www.google.com/accounts/OAuthGetAccessToken';
|
||||
$request = OAuthRequest::from_consumer_and_token($consumer, $token, 'GET', $url,
|
||||
array('oauth_verifier' => $_POST['oauth_verifier']));
|
||||
$request->sign_request($sigMethod, $consumer, $token);
|
||||
$response = send_signed_request('GET', $url, array($request->to_header()), null, false);
|
||||
$token = array();
|
||||
parse_str($response, $token);
|
||||
if (isset($token['oauth_token']) && isset($token['oauth_token_secret'])) {
|
||||
OCP\JSON::success(array('access_token' => $token['oauth_token'],
|
||||
'access_token_secret' => $token['oauth_token_secret']));
|
||||
} else {
|
||||
OCP\JSON::error(array('data' => array(
|
||||
'message' => 'Fetching access tokens failed. Error: '.$response
|
||||
)));
|
||||
}
|
||||
} else if ($step == 2 && isset($_POST['code'])) {
|
||||
try {
|
||||
$token = $client->authenticate($_POST['code']);
|
||||
OCP\JSON::success(array('data' => array(
|
||||
'token' => $token
|
||||
)));
|
||||
} catch (Exception $exception) {
|
||||
OCP\JSON::error(array('data' => array(
|
||||
'message' => 'Step 2 failed. Exception: '.$exception->getMessage()
|
||||
)));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,69 +1,89 @@
|
|||
$(document).ready(function() {
|
||||
|
||||
$('#externalStorage tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google').each(function(index, tr) {
|
||||
setupGoogleRow(tr);
|
||||
});
|
||||
|
||||
$('#externalStorage').on('change', '#selectBackend', function() {
|
||||
if ($(this).val() == '\\OC\\Files\\Storage\\Google') {
|
||||
setupGoogleRow($('#externalStorage tbody>tr:last').prev('tr'));
|
||||
}
|
||||
});
|
||||
|
||||
function setupGoogleRow(tr) {
|
||||
var configured = $(tr).find('[data-parameter="configured"]');
|
||||
$('#externalStorage tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google').each(function() {
|
||||
var configured = $(this).find('[data-parameter="configured"]');
|
||||
if ($(configured).val() == 'true') {
|
||||
$(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
|
||||
$(this).find('.configuration input').attr('disabled', 'disabled');
|
||||
$(this).find('.configuration').append($('<span/>').attr('id', 'access')
|
||||
.text(t('files_external', 'Access granted')));
|
||||
} else {
|
||||
var token = $(tr).find('[data-parameter="token"]');
|
||||
var token_secret = $(tr).find('[data-parameter="token_secret"]');
|
||||
var params = {};
|
||||
window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
|
||||
params[key] = value;
|
||||
});
|
||||
if (params['oauth_token'] !== undefined && params['oauth_verifier'] !== undefined && decodeURIComponent(params['oauth_token']) == $(token).val()) {
|
||||
var statusSpan = $(tr).find('.status span');
|
||||
statusSpan.removeClass();
|
||||
statusSpan.addClass('waiting');
|
||||
$.post(OC.filePath('files_external', 'ajax', 'google.php'), { step: 2, oauth_verifier: params['oauth_verifier'], request_token: $(token).val(), request_token_secret: $(token_secret).val() }, function(result) {
|
||||
if (result && result.status == 'success') {
|
||||
$(token).val(result.access_token);
|
||||
$(token_secret).val(result.access_token_secret);
|
||||
$(configured).val('true');
|
||||
OC.MountConfig.saveStorage(tr);
|
||||
$(tr).find('.configuration').append('<span id="access" style="padding-left:0.5em;">'+t('files_external', 'Access granted')+'</span>');
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Google Drive storage'));
|
||||
onGoogleInputsChange(tr);
|
||||
}
|
||||
var client_id = $(this).find('.configuration [data-parameter="client_id"]').val();
|
||||
var client_secret = $(this).find('.configuration [data-parameter="client_secret"]')
|
||||
.val();
|
||||
if (client_id != '' && client_secret != '') {
|
||||
var params = {};
|
||||
window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
|
||||
params[key] = value;
|
||||
});
|
||||
if (params['code'] !== undefined) {
|
||||
var tr = $(this);
|
||||
var token = $(this).find('.configuration [data-parameter="token"]');
|
||||
var statusSpan = $(tr).find('.status span');
|
||||
statusSpan.removeClass();
|
||||
statusSpan.addClass('waiting');
|
||||
$.post(OC.filePath('files_external', 'ajax', 'google.php'),
|
||||
{
|
||||
step: 2,
|
||||
client_id: client_id,
|
||||
client_secret: client_secret,
|
||||
redirect: location.protocol + '//' + location.host + location.pathname,
|
||||
code: params['code'],
|
||||
}, function(result) {
|
||||
if (result && result.status == 'success') {
|
||||
$(token).val(result.data.token);
|
||||
$(configured).val('true');
|
||||
OC.MountConfig.saveStorage(tr);
|
||||
$(tr).find('.configuration input').attr('disabled', 'disabled');
|
||||
$(tr).find('.configuration').append($('<span/>')
|
||||
.attr('id', 'access')
|
||||
.text(t('files_external', 'Access granted')));
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message,
|
||||
t('files_external', 'Error configuring Google Drive storage')
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
onGoogleInputsChange(tr);
|
||||
onGoogleInputsChange($(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$('#externalStorage').on('paste', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google td', function() {
|
||||
var tr = $(this).parent();
|
||||
setTimeout(function() {
|
||||
onGoogleInputsChange(tr);
|
||||
}, 20);
|
||||
});
|
||||
|
||||
$('#externalStorage').on('keyup', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google td', function() {
|
||||
onGoogleInputsChange($(this).parent());
|
||||
});
|
||||
$('#externalStorage').on('paste', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google td',
|
||||
function() {
|
||||
var tr = $(this).parent();
|
||||
setTimeout(function() {
|
||||
onGoogleInputsChange(tr);
|
||||
}, 20);
|
||||
}
|
||||
);
|
||||
|
||||
$('#externalStorage').on('change', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google .chzn-select', function() {
|
||||
onGoogleInputsChange($(this).parent().parent());
|
||||
});
|
||||
$('#externalStorage').on('keyup', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google td',
|
||||
function() {
|
||||
onGoogleInputsChange($(this).parent());
|
||||
}
|
||||
);
|
||||
|
||||
$('#externalStorage').on('change', 'tbody tr.\\\\OC\\\\Files\\\\Storage\\\\Google .chzn-select'
|
||||
, function() {
|
||||
onGoogleInputsChange($(this).parent().parent());
|
||||
}
|
||||
);
|
||||
|
||||
function onGoogleInputsChange(tr) {
|
||||
if ($(tr).find('[data-parameter="configured"]').val() != 'true') {
|
||||
var config = $(tr).find('.configuration');
|
||||
if ($(tr).find('.mountPoint input').val() != '' && ($(tr).find('.chzn-select').length == 0 || $(tr).find('.chzn-select').val() != null)) {
|
||||
if ($(tr).find('.mountPoint input').val() != ''
|
||||
&& $(config).find('[data-parameter="client_id"]').val() != ''
|
||||
&& $(config).find('[data-parameter="client_secret"]').val() != ''
|
||||
&& ($(tr).find('.chzn-select').length == 0
|
||||
|| $(tr).find('.chzn-select').val() != null))
|
||||
{
|
||||
if ($(tr).find('.google').length == 0) {
|
||||
$(config).append('<a class="button google">'+t('files_external', 'Grant access')+'</a>');
|
||||
$(config).append($('<a/>').addClass('button google')
|
||||
.text(t('files_external', 'Grant access')));
|
||||
} else {
|
||||
$(tr).find('.google').show();
|
||||
}
|
||||
|
@ -77,22 +97,33 @@ $(document).ready(function() {
|
|||
event.preventDefault();
|
||||
var tr = $(this).parent().parent();
|
||||
var configured = $(this).parent().find('[data-parameter="configured"]');
|
||||
var token = $(this).parent().find('[data-parameter="token"]');
|
||||
var token_secret = $(this).parent().find('[data-parameter="token_secret"]');
|
||||
var client_id = $(this).parent().find('[data-parameter="client_id"]').val();
|
||||
var client_secret = $(this).parent().find('[data-parameter="client_secret"]').val();
|
||||
var statusSpan = $(tr).find('.status span');
|
||||
$.post(OC.filePath('files_external', 'ajax', 'google.php'), { step: 1, callback: location.protocol + '//' + location.host + location.pathname }, function(result) {
|
||||
if (result && result.status == 'success') {
|
||||
$(configured).val('false');
|
||||
$(token).val(result.data.request_token);
|
||||
$(token_secret).val(result.data.request_token_secret);
|
||||
OC.MountConfig.saveStorage(tr);
|
||||
statusSpan.removeClass();
|
||||
statusSpan.addClass('waiting');
|
||||
window.location = result.data.url;
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message, t('files_external', 'Error configuring Google Drive storage'));
|
||||
}
|
||||
});
|
||||
if (client_id != '' && client_secret != '') {
|
||||
var token = $(this).parent().find('[data-parameter="token"]');
|
||||
$.post(OC.filePath('files_external', 'ajax', 'google.php'),
|
||||
{
|
||||
step: 1,
|
||||
client_id: client_id,
|
||||
client_secret: client_secret,
|
||||
redirect: location.protocol + '//' + location.host + location.pathname,
|
||||
}, function(result) {
|
||||
if (result && result.status == 'success') {
|
||||
$(configured).val('false');
|
||||
$(token).val('false');
|
||||
OC.MountConfig.saveStorage(tr);
|
||||
statusSpan.removeClass();
|
||||
statusSpan.addClass('waiting');
|
||||
window.location = result.data.url;
|
||||
} else {
|
||||
OC.dialogs.alert(result.data.message,
|
||||
t('files_external', 'Error configuring Google Drive storage')
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
|
@ -74,8 +74,9 @@ class OC_Mount_Config {
|
|||
'backend' => 'Google Drive',
|
||||
'configuration' => array(
|
||||
'configured' => '#configured',
|
||||
'token' => '#token',
|
||||
'token_secret' => '#token secret'),
|
||||
'client_id' => 'Client ID',
|
||||
'client_secret' => 'Client secret',
|
||||
'token' => '#token'),
|
||||
'custom' => 'google');
|
||||
|
||||
$backends['\OC\Files\Storage\SWIFT']=array(
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* ownCloud
|
||||
*
|
||||
|
@ -22,213 +21,161 @@
|
|||
|
||||
namespace OC\Files\Storage;
|
||||
|
||||
require_once 'Google/common.inc.php';
|
||||
require_once 'google-api-php-client/src/Google_Client.php';
|
||||
require_once 'google-api-php-client/src/contrib/Google_DriveService.php';
|
||||
|
||||
class Google extends \OC\Files\Storage\Common {
|
||||
|
||||
private $consumer;
|
||||
private $oauth_token;
|
||||
private $sig_method;
|
||||
private $entries;
|
||||
private $id;
|
||||
private $service;
|
||||
private $driveFiles;
|
||||
|
||||
private static $tempFiles = array();
|
||||
|
||||
// Google Doc mimetypes
|
||||
const FOLDER = 'application/vnd.google-apps.folder';
|
||||
const DOCUMENT = 'application/vnd.google-apps.document';
|
||||
const SPREADSHEET = 'application/vnd.google-apps.spreadsheet';
|
||||
const DRAWING = 'application/vnd.google-apps.drawing';
|
||||
const PRESENTATION = 'application/vnd.google-apps.presentation';
|
||||
|
||||
public function __construct($params) {
|
||||
if (isset($params['configured']) && $params['configured'] == 'true'
|
||||
if (isset($params['configured']) && $params['configured'] === 'true'
|
||||
&& isset($params['client_id']) && isset($params['client_secret'])
|
||||
&& isset($params['token'])
|
||||
&& isset($params['token_secret'])
|
||||
) {
|
||||
$consumer_key = isset($params['consumer_key']) ? $params['consumer_key'] : 'anonymous';
|
||||
$consumer_secret = isset($params['consumer_secret']) ? $params['consumer_secret'] : 'anonymous';
|
||||
$this->id = 'google::' . $params['token'];
|
||||
$this->consumer = new \OAuthConsumer($consumer_key, $consumer_secret);
|
||||
$this->oauth_token = new \OAuthToken($params['token'], $params['token_secret']);
|
||||
$this->sig_method = new \OAuthSignatureMethod_HMAC_SHA1();
|
||||
$this->entries = array();
|
||||
$client = new \Google_Client();
|
||||
$client->setClientId($params['client_id']);
|
||||
$client->setClientSecret($params['client_secret']);
|
||||
$client->setRedirectUri('http://localhost/workspace/core');
|
||||
$client->setScopes(array('https://www.googleapis.com/auth/drive'));
|
||||
$client->setUseObjects(true);
|
||||
$client->setAccessToken($params['token']);
|
||||
$this->service = new \Google_DriveService($client);
|
||||
$this->root = isset($params['root']) ? $params['root'] : '';
|
||||
$token = json_decode($params['token'], true);
|
||||
$this->id = 'google::'.$params['client_id'].$token['created'];
|
||||
} else {
|
||||
throw new \Exception('Creating \OC\Files\Storage\Google storage failed');
|
||||
}
|
||||
}
|
||||
|
||||
private function sendRequest($uri,
|
||||
$httpMethod,
|
||||
$postData = null,
|
||||
$extraHeaders = null,
|
||||
$isDownload = false,
|
||||
$returnHeaders = false,
|
||||
$isContentXML = true,
|
||||
$returnHTTPCode = false) {
|
||||
$uri = trim($uri);
|
||||
// create an associative array from each key/value url query param pair.
|
||||
$params = array();
|
||||
$pieces = explode('?', $uri);
|
||||
if (isset($pieces[1])) {
|
||||
$params = explode_assoc('=', '&', $pieces[1]);
|
||||
}
|
||||
// urlencode each url parameter key/value pair
|
||||
$tempStr = $pieces[0];
|
||||
foreach ($params as $key => $value) {
|
||||
$tempStr .= '&' . urlencode($key) . '=' . urlencode($value);
|
||||
}
|
||||
$uri = preg_replace('/&/', '?', $tempStr, 1);
|
||||
$request = \OAuthRequest::from_consumer_and_token($this->consumer,
|
||||
$this->oauth_token,
|
||||
$httpMethod,
|
||||
$uri,
|
||||
$params);
|
||||
$request->sign_request($this->sig_method, $this->consumer, $this->oauth_token);
|
||||
$auth_header = $request->to_header();
|
||||
$headers = array($auth_header, 'GData-Version: 3.0');
|
||||
if ($isContentXML) {
|
||||
$headers = array_merge($headers, array('Content-Type: application/atom+xml'));
|
||||
}
|
||||
if (is_array($extraHeaders)) {
|
||||
$headers = array_merge($headers, $extraHeaders);
|
||||
}
|
||||
$curl = curl_init($uri);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_FAILONERROR, false);
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
switch ($httpMethod) {
|
||||
case 'GET':
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
break;
|
||||
case 'POST':
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_POST, 1);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
|
||||
break;
|
||||
case 'PUT':
|
||||
$headers[] = 'If-Match: *';
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $httpMethod);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
|
||||
break;
|
||||
case 'DELETE':
|
||||
$headers[] = 'If-Match: *';
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $httpMethod);
|
||||
break;
|
||||
default:
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
}
|
||||
if ($isDownload) {
|
||||
$tmpFile = \OC_Helper::tmpFile();
|
||||
$handle = fopen($tmpFile, 'w');
|
||||
curl_setopt($curl, CURLOPT_FILE, $handle);
|
||||
}
|
||||
if ($returnHeaders) {
|
||||
curl_setopt($curl, CURLOPT_HEADER, true);
|
||||
}
|
||||
$result = curl_exec($curl);
|
||||
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
curl_close($curl);
|
||||
if ($result) {
|
||||
// TODO https://developers.google.com/google-apps/documents-list/#handling_api_errors
|
||||
// TODO Log error messages
|
||||
if ($httpCode <= 308) {
|
||||
if ($isDownload) {
|
||||
return $tmpFile;
|
||||
} else if ($returnHTTPCode) {
|
||||
return array('result' => $result, 'code' => $httpCode);
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getFeed($feedUri, $httpMethod, $postData = null) {
|
||||
$result = $this->sendRequest($feedUri, $httpMethod, $postData);
|
||||
if ($result) {
|
||||
$dom = new \DOMDocument();
|
||||
$dom->loadXML($result);
|
||||
return $dom;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Base url for google docs feeds
|
||||
*/
|
||||
const BASE_URI='https://docs.google.com/feeds';
|
||||
|
||||
private function getResource($path) {
|
||||
$file = basename($path);
|
||||
if (array_key_exists($file, $this->entries)) {
|
||||
return $this->entries[$file];
|
||||
} else {
|
||||
// Strip the file extension; file could be a native Google Docs resource
|
||||
if ($pos = strpos($file, '.')) {
|
||||
$title = substr($file, 0, $pos);
|
||||
$dom = $this->getFeed(self::BASE_URI.'/default/private/full?showfolders=true&title='.$title, 'GET');
|
||||
// Check if request was successful and entry exists
|
||||
if ($dom && $entry = $dom->getElementsByTagName('entry')->item(0)) {
|
||||
$this->entries[$file] = $entry;
|
||||
return $entry;
|
||||
}
|
||||
}
|
||||
$dom = $this->getFeed(self::BASE_URI.'/default/private/full?showfolders=true&title='.$file, 'GET');
|
||||
// Check if request was successful and entry exists
|
||||
if ($dom && $entry = $dom->getElementsByTagName('entry')->item(0)) {
|
||||
$this->entries[$file] = $entry;
|
||||
return $entry;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function getExtension($entry) {
|
||||
$mimetype = $this->getMimeType('', $entry);
|
||||
switch ($mimetype) {
|
||||
case 'httpd/unix-directory':
|
||||
return '';
|
||||
case 'application/vnd.oasis.opendocument.text':
|
||||
return 'odt';
|
||||
case 'application/vnd.oasis.opendocument.spreadsheet':
|
||||
return 'ods';
|
||||
case 'application/vnd.oasis.opendocument.presentation':
|
||||
return 'pptx';
|
||||
case 'text/html':
|
||||
return 'html';
|
||||
default:
|
||||
return 'html';
|
||||
}
|
||||
}
|
||||
|
||||
public function getId(){
|
||||
public function getId() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function mkdir($path) {
|
||||
$collection = dirname($path);
|
||||
// Check if path parent is root directory
|
||||
if ($collection == '/' || $collection == '\.' || $collection == '.') {
|
||||
$uri = self::BASE_URI.'/default/private/full';
|
||||
/**
|
||||
* Get the Google_DriveFile object for the specified path
|
||||
* @param string $path
|
||||
* @return Google_DriveFile
|
||||
*/
|
||||
private function getDriveFile($path) {
|
||||
// Remove leading and trailing slashes
|
||||
$path = trim($this->root.$path, '/');
|
||||
if (isset($this->driveFiles[$path])) {
|
||||
return $this->driveFiles[$path];
|
||||
} else if ($path === '') {
|
||||
$root = $this->service->files->get('root');
|
||||
$this->driveFiles[$path] = $root;
|
||||
return $root;
|
||||
} else {
|
||||
// Get parent content link
|
||||
$dom = $this->getResource(basename($collection));
|
||||
if ($dom) {
|
||||
$uri = $dom->getElementsByTagName('content')->item(0)->getAttribute('src');
|
||||
// Google Drive SDK does not have methods for retrieving files by path
|
||||
// Instead we must find the id of the parent folder of the file
|
||||
$parentId = $this->getDriveFile('')->getId();
|
||||
$folderNames = explode('/', $path);
|
||||
$path = '';
|
||||
// Loop through each folder of this path to get to the file
|
||||
foreach ($folderNames as $name) {
|
||||
// Reconstruct path from beginning
|
||||
if ($path === '') {
|
||||
$path .= $name;
|
||||
} else {
|
||||
$path .= '/'.$name;
|
||||
}
|
||||
if (isset($this->driveFiles[$path])) {
|
||||
$parentId = $this->driveFiles[$path]->getId();
|
||||
} else {
|
||||
$q = "title='".$name."' and '".$parentId."' in parents";
|
||||
$result = $this->service->files->listFiles(array('q' => $q))->getItems();
|
||||
if (!empty($result)) {
|
||||
// Google Drive allows files with the same name, ownCloud doesn't
|
||||
if (count($result) > 1) {
|
||||
$this->onDuplicateFileDetected($path);
|
||||
return false;
|
||||
} else {
|
||||
$file = current($result);
|
||||
$this->driveFiles[$path] = $file;
|
||||
$parentId = $file->getId();
|
||||
}
|
||||
} else {
|
||||
// Google Docs have no extension in their title, so try without extension
|
||||
$pos = strrpos($path, '.');
|
||||
if ($pos !== false) {
|
||||
$pathWithoutExt = substr($path, 0, $pos);
|
||||
$file = $this->getDriveFile($pathWithoutExt);
|
||||
if ($file) {
|
||||
// Switch cached Google_DriveFile to the correct index
|
||||
unset($this->driveFiles[$pathWithoutExt]);
|
||||
$this->driveFiles[$path] = $file;
|
||||
$parentId = $file->getId();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->driveFiles[$path];
|
||||
}
|
||||
if (isset($uri)) {
|
||||
$title = basename($path);
|
||||
// Construct post data
|
||||
$postData = '<?xml version="1.0" encoding="UTF-8"?>';
|
||||
$postData .= '<entry xmlns="http://www.w3.org/2005/Atom">';
|
||||
$postData .= '<category scheme="http://schemas.google.com/g/2005#kind"';
|
||||
$postData .= ' term="http://schemas.google.com/docs/2007#folder"/>';
|
||||
$postData .= '<title>'.$title.'</title>';
|
||||
$postData .= '</entry>';
|
||||
$dom = $this->sendRequest($uri, 'POST', $postData);
|
||||
if ($dom) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a log message to inform about duplicate file names
|
||||
* @param string $path
|
||||
*/
|
||||
private function onDuplicateFileDetected($path) {
|
||||
$about = $this->service->about->get();
|
||||
$user = $about->getName();
|
||||
\OCP\Util::writeLog('files_external',
|
||||
'Ignoring duplicate file name: '.$path.' on Google Drive for Google user: '.$user,
|
||||
\OCP\Util::INFO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate file extension for a Google Doc, choosing Open Document formats for download
|
||||
* @param string $mimetype
|
||||
* @return string
|
||||
*/
|
||||
private function getGoogleDocExtension($mimetype) {
|
||||
if ($mimetype === self::DOCUMENT) {
|
||||
return 'odt';
|
||||
} else if ($mimetype === self::SPREADSHEET) {
|
||||
return 'ods';
|
||||
} else if ($mimetype === self::DRAWING) {
|
||||
return 'jpg';
|
||||
} else if ($mimetype === self::PRESENTATION) {
|
||||
// Download as .odp is not available
|
||||
return 'pdf';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function mkdir($path) {
|
||||
$parentFolder = $this->getDriveFile(dirname($path));
|
||||
if ($parentFolder) {
|
||||
$folder = new \Google_DriveFile();
|
||||
$folder->setTitle(basename($path));
|
||||
$folder->setMimeType(self::FOLDER);
|
||||
$parent = new \Google_ParentReference();
|
||||
$parent->setId($parentFolder->getId());
|
||||
$folder->setParents(array($parent));
|
||||
return (bool)$this->service->files->insert($folder);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function rmdir($path) {
|
||||
|
@ -236,92 +183,98 @@ class Google extends \OC\Files\Storage\Common {
|
|||
}
|
||||
|
||||
public function opendir($path) {
|
||||
if ($path == '' || $path == '/') {
|
||||
$next = self::BASE_URI.'/default/private/full/folder%3Aroot/contents';
|
||||
// Remove leading and trailing slashes
|
||||
$path = trim($path, '/');
|
||||
$folder = $this->getDriveFile($path);
|
||||
if ($folder) {
|
||||
$files = array();
|
||||
$duplicates = array();
|
||||
$pageToken = true;
|
||||
while ($pageToken) {
|
||||
$params = array();
|
||||
if ($pageToken !== true) {
|
||||
$params['pageToken'] = $pageToken;
|
||||
}
|
||||
$params['q'] = "'".$folder->getId()."' in parents";
|
||||
$children = $this->service->files->listFiles($params);
|
||||
foreach ($children->getItems() as $child) {
|
||||
$name = $child->getTitle();
|
||||
// Check if this is a Google Doc i.e. no extension in name
|
||||
if ($child->getFileExtension() == ''
|
||||
&& $child->getMimeType() !== self::FOLDER
|
||||
) {
|
||||
$name .= '.'.$this->getGoogleDocExtension($child->getMimeType());
|
||||
}
|
||||
if ($path === '') {
|
||||
$filepath = $name;
|
||||
} else {
|
||||
$filepath = $path.'/'.$name;
|
||||
}
|
||||
// Google Drive allows files with the same name, ownCloud doesn't
|
||||
// Prevent opendir() from returning any duplicate files
|
||||
if (isset($this->driveFiles[$filepath]) && !isset($duplicates[$filepath])) {
|
||||
// Save this key to unset later in case there are more than 2 duplicates
|
||||
$duplicates[$filepath] = $name;
|
||||
} else {
|
||||
// Cache the Google_DriveFile for future use
|
||||
$this->driveFiles[$filepath] = $child;
|
||||
$files[] = $name;
|
||||
}
|
||||
}
|
||||
$pageToken = $children->getNextPageToken();
|
||||
}
|
||||
// Remove all duplicate files
|
||||
foreach ($duplicates as $filepath => $name) {
|
||||
unset($this->driveFiles[$filepath]);
|
||||
$key = array_search($name, $files);
|
||||
unset($files[$key]);
|
||||
$this->onDuplicateFileDetected($filepath);
|
||||
}
|
||||
// Reindex $files array if duplicates were removed
|
||||
// This is necessary for \OC\Files\Stream\Dir
|
||||
if (!empty($duplicates)) {
|
||||
$files = array_values($files);
|
||||
}
|
||||
\OC\Files\Stream\Dir::register('google'.$path, $files);
|
||||
return opendir('fakedir://google'.$path);
|
||||
} else {
|
||||
$entry = $this->getResource($path);
|
||||
if ($entry) {
|
||||
$next = $entry->getElementsByTagName('content')->item(0)->getAttribute('src');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function stat($path) {
|
||||
$file = $this->getDriveFile($path);
|
||||
if ($file) {
|
||||
$stat = array();
|
||||
if ($this->filetype($path) === 'dir') {
|
||||
$stat['size'] = 0;
|
||||
} else {
|
||||
$stat['size'] = $file->getFileSize();
|
||||
}
|
||||
$stat['atime'] = strtotime($file->getLastViewedByMeDate());
|
||||
$stat['mtime'] = strtotime($file->getModifiedDate());
|
||||
$stat['ctime'] = strtotime($file->getCreatedDate());
|
||||
return $stat;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function filetype($path) {
|
||||
if ($path === '') {
|
||||
return 'dir';
|
||||
} else {
|
||||
$file = $this->getDriveFile($path);
|
||||
if ($file) {
|
||||
if ($file->getMimeType() === self::FOLDER) {
|
||||
return 'dir';
|
||||
} else {
|
||||
return 'file';
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$files = array();
|
||||
while ($next) {
|
||||
$dom = $this->getFeed($next, 'GET');
|
||||
$links = $dom->getElementsByTagName('link');
|
||||
foreach ($links as $link) {
|
||||
if ($link->getAttribute('rel') == 'next') {
|
||||
$next = $link->getAttribute('src');
|
||||
break;
|
||||
} else {
|
||||
$next = false;
|
||||
}
|
||||
}
|
||||
$entries = $dom->getElementsByTagName('entry');
|
||||
foreach ($entries as $entry) {
|
||||
$name = $entry->getElementsByTagName('title')->item(0)->nodeValue;
|
||||
// Google Docs resources don't always include extensions in title
|
||||
if ( ! strpos($name, '.')) {
|
||||
$extension = $this->getExtension($entry);
|
||||
if ($extension != '') {
|
||||
$name .= '.'.$extension;
|
||||
}
|
||||
}
|
||||
$files[] = basename($name);
|
||||
// Cache entry for future use
|
||||
$this->entries[$name] = $entry;
|
||||
}
|
||||
}
|
||||
\OC\Files\Stream\Dir::register('google'.$path, $files);
|
||||
return opendir('fakedir://google'.$path);
|
||||
}
|
||||
|
||||
public function stat($path) {
|
||||
if ($path == '' || $path == '/') {
|
||||
$stat['size'] = $this->free_space($path);
|
||||
$stat['atime'] = time();
|
||||
$stat['mtime'] = time();
|
||||
$stat['ctime'] = time();
|
||||
} else {
|
||||
$entry = $this->getResource($path);
|
||||
if ($entry) {
|
||||
// NOTE: Native resources don't have a file size
|
||||
$stat['size'] = $entry->getElementsByTagNameNS('http://schemas.google.com/g/2005',
|
||||
'quotaBytesUsed')->item(0)->nodeValue;
|
||||
//if (isset($atime = $entry->getElementsByTagNameNS('http://schemas.google.com/g/2005',
|
||||
// 'lastViewed')->item(0)->nodeValue))
|
||||
//$stat['atime'] = strtotime($entry->getElementsByTagNameNS('http://schemas.google.com/g/2005',
|
||||
// 'lastViewed')->item(0)->nodeValue);
|
||||
$stat['mtime'] = strtotime($entry->getElementsByTagName('updated')->item(0)->nodeValue);
|
||||
}
|
||||
}
|
||||
if (isset($stat)) {
|
||||
return $stat;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function filetype($path) {
|
||||
if ($path == '' || $path == '/') {
|
||||
return 'dir';
|
||||
} else {
|
||||
$entry = $this->getResource($path);
|
||||
if ($entry) {
|
||||
$categories = $entry->getElementsByTagName('category');
|
||||
foreach ($categories as $category) {
|
||||
if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') {
|
||||
$type = $category->getAttribute('label');
|
||||
if (strlen(strstr($type, 'folder')) > 0) {
|
||||
return 'dir';
|
||||
} else {
|
||||
return 'file';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isReadable($path) {
|
||||
|
@ -329,109 +282,79 @@ class Google extends \OC\Files\Storage\Common {
|
|||
}
|
||||
|
||||
public function isUpdatable($path) {
|
||||
if ($path == '' || $path == '/') {
|
||||
return true;
|
||||
$file = $this->getDriveFile($path);
|
||||
if ($file) {
|
||||
return $file->getEditable();
|
||||
} else {
|
||||
$entry = $this->getResource($path);
|
||||
if ($entry) {
|
||||
// Check if edit or edit-media links exist
|
||||
$links = $entry->getElementsByTagName('link');
|
||||
foreach ($links as $link) {
|
||||
if ($link->getAttribute('rel') == 'edit') {
|
||||
return true;
|
||||
} else if ($link->getAttribute('rel') == 'edit-media') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function file_exists($path) {
|
||||
if ($path == '' || $path == '/') {
|
||||
return true;
|
||||
} else if ($this->getResource($path)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return (bool)$this->getDriveFile($path);
|
||||
}
|
||||
|
||||
public function unlink($path) {
|
||||
// Get resource self link to trash resource
|
||||
$entry = $this->getResource($path);
|
||||
if ($entry) {
|
||||
$links = $entry->getElementsByTagName('link');
|
||||
foreach ($links as $link) {
|
||||
if ($link->getAttribute('rel') == 'self') {
|
||||
$uri = $link->getAttribute('href');
|
||||
break;
|
||||
}
|
||||
}
|
||||
$file = $this->getDriveFile($path);
|
||||
if ($file) {
|
||||
return (bool)$this->service->files->trash($file->getId());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (isset($uri)) {
|
||||
$this->sendRequest($uri, 'DELETE');
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function rename($path1, $path2) {
|
||||
$entry = $this->getResource($path1);
|
||||
if ($entry) {
|
||||
$collection = dirname($path2);
|
||||
if (dirname($path1) == $collection) {
|
||||
// Get resource edit link to rename resource
|
||||
$etag = $entry->getAttribute('gd:etag');
|
||||
$links = $entry->getElementsByTagName('link');
|
||||
foreach ($links as $link) {
|
||||
if ($link->getAttribute('rel') == 'edit') {
|
||||
$uri = $link->getAttribute('href');
|
||||
break;
|
||||
}
|
||||
}
|
||||
$title = basename($path2);
|
||||
// Construct post data
|
||||
$postData = '<?xml version="1.0" encoding="UTF-8"?>';
|
||||
$postData .= '<entry xmlns="http://www.w3.org/2005/Atom"';
|
||||
$postData .= ' xmlns:docs="http://schemas.google.com/docs/2007"';
|
||||
$postData .= ' xmlns:gd="http://schemas.google.com/g/2005"';
|
||||
$postData .= ' gd:etag='.$etag.'>';
|
||||
$postData .= '<title>'.$title.'</title>';
|
||||
$postData .= '</entry>';
|
||||
$this->sendRequest($uri, 'PUT', $postData);
|
||||
return true;
|
||||
$file = $this->getDriveFile($path1);
|
||||
if ($file) {
|
||||
if (dirname($path1) === dirname($path2)) {
|
||||
$file->setTitle(basename(($path2)));
|
||||
} else {
|
||||
// Move to different collection
|
||||
$collectionEntry = $this->getResource($collection);
|
||||
if ($collectionEntry) {
|
||||
$feedUri = $collectionEntry->getElementsByTagName('content')->item(0)->getAttribute('src');
|
||||
// Construct post data
|
||||
$postData = '<?xml version="1.0" encoding="UTF-8"?>';
|
||||
$postData .= '<entry xmlns="http://www.w3.org/2005/Atom">';
|
||||
$postData .= '<id>'.$entry->getElementsByTagName('id')->item(0).'</id>';
|
||||
$postData .= '</entry>';
|
||||
$this->sendRequest($feedUri, 'POST', $postData);
|
||||
return true;
|
||||
// Change file parent
|
||||
$parentFolder2 = $this->getDriveFile(dirname($path2));
|
||||
if ($parentFolder2) {
|
||||
$parent = new \Google_ParentReference();
|
||||
$parent->setId($parentFolder2->getId());
|
||||
$file->setParents(array($parent));
|
||||
}
|
||||
}
|
||||
return (bool)$this->service->files->patch($file->getId(), $file);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function fopen($path, $mode) {
|
||||
$pos = strrpos($path, '.');
|
||||
if ($pos !== false) {
|
||||
$ext = substr($path, $pos);
|
||||
} else {
|
||||
$ext = '';
|
||||
}
|
||||
switch ($mode) {
|
||||
case 'r':
|
||||
case 'rb':
|
||||
$entry = $this->getResource($path);
|
||||
if ($entry) {
|
||||
$extension = $this->getExtension($entry);
|
||||
$downloadUri = $entry->getElementsByTagName('content')->item(0)->getAttribute('src');
|
||||
// TODO Non-native documents don't need these additional parameters
|
||||
$downloadUri .= '&exportFormat='.$extension.'&format='.$extension;
|
||||
$tmpFile = $this->sendRequest($downloadUri, 'GET', null, null, true);
|
||||
return fopen($tmpFile, 'r');
|
||||
$file = $this->getDriveFile($path);
|
||||
if ($file) {
|
||||
$exportLinks = $file->getExportLinks();
|
||||
$mimetype = $this->getMimeType($path);
|
||||
$downloadUrl = null;
|
||||
if ($exportLinks && isset($exportLinks[$mimetype])) {
|
||||
$downloadUrl = $exportLinks[$mimetype];
|
||||
} else {
|
||||
$downloadUrl = $file->getDownloadUrl();
|
||||
}
|
||||
if (isset($downloadUrl)) {
|
||||
$request = new \Google_HttpRequest($downloadUrl, 'GET', null, null);
|
||||
$httpRequest = \Google_Client::$io->authenticatedRequest($request);
|
||||
if ($httpRequest->getResponseHttpCode() == 200) {
|
||||
$tmpFile = \OC_Helper::tmpFile($ext);
|
||||
$data = $httpRequest->getResponseBody();
|
||||
file_put_contents($tmpFile, $data);
|
||||
return fopen($tmpFile, $mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
case 'w':
|
||||
case 'wb':
|
||||
case 'a':
|
||||
|
@ -444,156 +367,88 @@ class Google extends \OC\Files\Storage\Common {
|
|||
case 'x+':
|
||||
case 'c':
|
||||
case 'c+':
|
||||
if (strrpos($path, '.') !== false) {
|
||||
$ext = substr($path, strrpos($path, '.'));
|
||||
} else {
|
||||
$ext = '';
|
||||
}
|
||||
$tmpFile = \OC_Helper::tmpFile($ext);
|
||||
\OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
|
||||
if ($this->file_exists($path)) {
|
||||
$source = $this->fopen($path, 'r');
|
||||
$source = $this->fopen($path, 'rb');
|
||||
file_put_contents($tmpFile, $source);
|
||||
}
|
||||
self::$tempFiles[$tmpFile] = $path;
|
||||
return fopen('close://'.$tmpFile, $mode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function writeBack($tmpFile) {
|
||||
if (isset(self::$tempFiles[$tmpFile])) {
|
||||
$this->uploadFile($tmpFile, self::$tempFiles[$tmpFile]);
|
||||
$path = self::$tempFiles[$tmpFile];
|
||||
$parentFolder = $this->getDriveFile(dirname($path));
|
||||
if ($parentFolder) {
|
||||
$file = new \Google_DriveFile();
|
||||
$file->setTitle(basename($path));
|
||||
$mimetype = \OC_Helper::getMimeType($tmpFile);
|
||||
$file->setMimeType($mimetype);
|
||||
$parent = new \Google_ParentReference();
|
||||
$parent->setId($parentFolder->getId());
|
||||
$file->setParents(array($parent));
|
||||
// TODO Research resumable upload
|
||||
$data = file_get_contents($tmpFile);
|
||||
$params = array(
|
||||
'data' => $data,
|
||||
'mimeType' => $mimetype,
|
||||
);
|
||||
if ($this->file_exists($path)) {
|
||||
$this->service->files->update($file->getId(), $file, $params);
|
||||
} else {
|
||||
$this->service->files->insert($file, $params);
|
||||
}
|
||||
}
|
||||
unlink($tmpFile);
|
||||
}
|
||||
}
|
||||
|
||||
private function uploadFile($path, $target) {
|
||||
$entry = $this->getResource($target);
|
||||
if ( ! $entry) {
|
||||
if (dirname($target) == '.' || dirname($target) == '/') {
|
||||
$uploadUri = self::BASE_URI.'/upload/create-session/default/private/full/folder%3Aroot/contents';
|
||||
} else {
|
||||
$entry = $this->getResource(dirname($target));
|
||||
}
|
||||
}
|
||||
if ( ! isset($uploadUri) && $entry) {
|
||||
$links = $entry->getElementsByTagName('link');
|
||||
foreach ($links as $link) {
|
||||
if ($link->getAttribute('rel') == 'http://schemas.google.com/g/2005#resumable-create-media') {
|
||||
$uploadUri = $link->getAttribute('href');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($uploadUri) && $handle = fopen($path, 'r')) {
|
||||
$uploadUri .= '?convert=false';
|
||||
$mimetype = \OC_Helper::getMimeType($path);
|
||||
$size = filesize($path);
|
||||
$headers = array('X-Upload-Content-Type: ' => $mimetype, 'X-Upload-Content-Length: ' => $size);
|
||||
$postData = '<?xml version="1.0" encoding="UTF-8"?>';
|
||||
$postData .= '<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">';
|
||||
$postData .= '<title>'.basename($target).'</title>';
|
||||
$postData .= '</entry>';
|
||||
$result = $this->sendRequest($uploadUri, 'POST', $postData, $headers, false, true);
|
||||
if ($result) {
|
||||
// Get location to upload file
|
||||
if (preg_match('@^Location: (.*)$@m', $result, $matches)) {
|
||||
$uploadUri = trim($matches[1]);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
// 512 kB chunks
|
||||
$chunkSize = 524288;
|
||||
$i = 0;
|
||||
while (!feof($handle)) {
|
||||
if ($i + $chunkSize > $size) {
|
||||
if ($i == 0) {
|
||||
$chunkSize = $size;
|
||||
} else {
|
||||
$chunkSize = $size % $i;
|
||||
}
|
||||
}
|
||||
$end = $i + $chunkSize - 1;
|
||||
$headers = array('Content-Length: '.$chunkSize,
|
||||
'Content-Type: '.$mimetype,
|
||||
'Content-Range: bytes '.$i.'-'.$end.'/'.$size);
|
||||
$postData = fread($handle, $chunkSize);
|
||||
$result = $this->sendRequest($uploadUri, 'PUT', $postData, $headers, false, true, false, true);
|
||||
if ($result['code'] == '308') {
|
||||
if (preg_match('@^Location: (.*)$@m', $result['result'], $matches)) {
|
||||
// Get next location to upload file chunk
|
||||
$uploadUri = trim($matches[1]);
|
||||
}
|
||||
$i += $chunkSize;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// TODO Wait for resource entry
|
||||
}
|
||||
}
|
||||
|
||||
public function getMimeType($path, $entry = null) {
|
||||
// Entry can be passed, because extension is required for opendir
|
||||
// and the entry can't be cached without the extension
|
||||
if ($entry == null) {
|
||||
if ($path == '' || $path == '/') {
|
||||
public function getMimeType($path) {
|
||||
$file = $this->getDriveFile($path);
|
||||
if ($file) {
|
||||
$mimetype = $file->getMimeType();
|
||||
// Convert Google Doc mimetypes, choosing Open Document formats for download
|
||||
if ($mimetype === self::FOLDER) {
|
||||
return 'httpd/unix-directory';
|
||||
} else if ($mimetype === self::DOCUMENT) {
|
||||
return 'application/vnd.oasis.opendocument.text';
|
||||
} else if ($mimetype === self::SPREADSHEET) {
|
||||
return 'application/x-vnd.oasis.opendocument.spreadsheet';
|
||||
} else if ($mimetype === self::DRAWING) {
|
||||
return 'image/jpeg';
|
||||
} else if ($mimetype === self::PRESENTATION) {
|
||||
// Download as .odp is not available
|
||||
return 'application/pdf';
|
||||
} else {
|
||||
$entry = $this->getResource($path);
|
||||
return $mimetype;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if ($entry) {
|
||||
$mimetype = $entry->getElementsByTagName('content')->item(0)->getAttribute('type');
|
||||
// Native Google Docs resources often default to text/html,
|
||||
// but it may be more useful to default to a corresponding ODF mimetype
|
||||
// Collections get reported as application/atom+xml,
|
||||
// make sure it actually is a folder and fix the mimetype
|
||||
if ($mimetype == 'text/html' || $mimetype == 'application/atom+xml;type=feed') {
|
||||
$categories = $entry->getElementsByTagName('category');
|
||||
foreach ($categories as $category) {
|
||||
if ($category->getAttribute('scheme') == 'http://schemas.google.com/g/2005#kind') {
|
||||
$type = $category->getAttribute('label');
|
||||
if (strlen(strstr($type, 'folder')) > 0) {
|
||||
return 'httpd/unix-directory';
|
||||
} else if (strlen(strstr($type, 'document')) > 0) {
|
||||
return 'application/vnd.oasis.opendocument.text';
|
||||
} else if (strlen(strstr($type, 'spreadsheet')) > 0) {
|
||||
return 'application/vnd.oasis.opendocument.spreadsheet';
|
||||
} else if (strlen(strstr($type, 'presentation')) > 0) {
|
||||
return 'application/vnd.oasis.opendocument.presentation';
|
||||
} else if (strlen(strstr($type, 'drawing')) > 0) {
|
||||
return 'application/vnd.oasis.opendocument.graphics';
|
||||
} else {
|
||||
// If nothing matches return text/html,
|
||||
// all native Google Docs resources can be exported as text/html
|
||||
return 'text/html';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $mimetype;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function free_space($path) {
|
||||
$dom = $this->getFeed(self::BASE_URI.'/metadata/default', 'GET');
|
||||
if ($dom) {
|
||||
// NOTE: Native Google Docs resources don't count towards quota
|
||||
$total = $dom->getElementsByTagNameNS('http://schemas.google.com/g/2005',
|
||||
'quotaBytesTotal')->item(0)->nodeValue;
|
||||
$used = $dom->getElementsByTagNameNS('http://schemas.google.com/g/2005',
|
||||
'quotaBytesUsed')->item(0)->nodeValue;
|
||||
return $total - $used;
|
||||
}
|
||||
return false;
|
||||
$about = $this->service->about->get();
|
||||
return $about->getQuotaBytesTotal() - $about->getQuotaBytesUsed();
|
||||
}
|
||||
|
||||
public function touch($path, $mtime = null) {
|
||||
|
||||
$file = $this->getDriveFile($path);
|
||||
if ($file) {
|
||||
if (isset($mtime)) {
|
||||
$file->setModifiedDate($mtime);
|
||||
$this->service->files->patch($file->getId(), $file, array(
|
||||
'setModifiedDate' => true,
|
||||
));
|
||||
} else {
|
||||
return (bool)$this->service->files->touch($file->getId());
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function test() {
|
||||
|
@ -603,4 +458,4 @@ class Google extends \OC\Files\Storage\Common {
|
|||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue