').text(str === null || typeof str === 'undefined' ? '' : str).html();
+}
+
+function ecmGoogleDriveRenderBreadcrumb()
+{
+ var html = '';
+ for (var i = 0; i < ecmGoogleDriveBreadcrumb.length; i++) {
+ if (i > 0) {
+ html += ' / ';
+ }
+ html += '
'+ecmGoogleDriveEscapeHtml(ecmGoogleDriveBreadcrumb[i].name)+'';
+ }
+ jQuery('#ecmgdrive-breadcrumb').html(html);
+}
+
+function ecmGoogleDriveGoToBreadcrumb(index)
+{
+ var entry = ecmGoogleDriveBreadcrumb[index];
+ ecmGoogleDriveBreadcrumb = ecmGoogleDriveBreadcrumb.slice(0, index + 1);
+ jQuery('#ecmgdrive_folderid').val(entry.id);
+ ecmGoogleDriveLoadList(entry.id);
+}
+
+function ecmGoogleDriveNavigate(folderid, foldername)
+{
+ ecmGoogleDriveBreadcrumb.push({id: folderid, name: foldername});
+ jQuery('#ecmgdrive_folderid').val(folderid);
+ ecmGoogleDriveLoadList(folderid);
+}
+
+function ecmGoogleDriveLoadList(folderid)
+{
+ ecmGoogleDriveRenderBreadcrumb();
+ jQuery('#ecmgdrive-filelist').html('trans("PleaseBePatient")); ?>');
+ jQuery.get('', {dir: folderid, token: ''}, function(data) {
+ jQuery('#ecmgdrive-filelist').html(data);
+ });
+}
+
+function ecmGoogleDriveRename(fileid, currentname)
+{
+ var newname = prompt('trans("GoogleApiNewName")); ?>', currentname);
+ if (newname === null || newname === '' || newname === currentname) {
+ return;
+ }
+ jQuery.post('', {
+ action: 'renamedrivefile',
+ token: '',
+ fileid: fileid,
+ newname: newname
+ }, function() {
+ ecmGoogleDriveLoadList(jQuery('#ecmgdrive_folderid').val());
+ });
+}
+
+function ecmGoogleDriveDelete(fileid, filename)
+{
+ var msgtemplate = 'trans("GoogleApiConfirmDeleteDriveFile")); ?>';
+ if (!confirm(msgtemplate.replace('__FILENAME__', filename))) {
+ return;
+ }
+ jQuery.post('', {
+ action: 'deletedrivefile',
+ token: '',
+ fileid: fileid
+ }, function() {
+ ecmGoogleDriveLoadList(jQuery('#ecmgdrive_folderid').val());
+ });
+}
+
+jQuery(document).ready(function() {
+ // Load the file list first, and isolate the folder tree init: a failure of the jqueryFileTree
+ // plugin (not loaded, error, ...) must never prevent the file list from being displayed.
+ ecmGoogleDriveLoadList('root');
+
+ try {
+ jQuery('#filetree').fileTree(
+ {
+ root: 'root/',
+ script: '?token=',
+ folderEvent: 'click',
+ multiFolder: false
+ },
+ function(file) {
+ // Files are not shown in the left tree (folders only): nothing to do here.
+ }
+ );
+ } catch (e) {
+ console.error('ecmgoogledrive: unable to initialize the folder tree', e);
+ }
+});
diff --git a/langs/en_US/googleapi.lang b/langs/en_US/googleapi.lang
index ba2d66b..ce42ff5 100644
--- a/langs/en_US/googleapi.lang
+++ b/langs/en_US/googleapi.lang
@@ -37,3 +37,16 @@ GoogleApiRemindByNotification=Google Notification Reminder
GoogleApiOwnerEmail=Google email of the connected account
GoogleApiCalendarTZ=Google Calendar Timezone
GoogleApiIdId=Google Resource ID
+GoogleApiDriveTab=Google Drive
+GoogleApiDriveNotConnected=Your Google account is not connected yet, or the access token has expired.
+GoogleApiConnectDrive=Connect to Google Drive
+GoogleApiFolder=Folder
+GoogleApiRename=Rename
+GoogleApiNewName=New name
+GoogleApiOpenInDrive=Open in Drive
+GoogleApiConfirmDeleteDriveFile=Are you sure you want to move "__FILENAME__" to the Google Drive trash?
+GoogleApiUploadToThisFolder=Upload a file into this folder
+GoogleApiDriveFileUploaded=File uploaded to Google Drive
+GoogleApiDriveFileRenamed=Renamed on Google Drive
+GoogleApiDriveFileDeleted=Moved to the Google Drive trash
+GoogleApiErrorDriveApi=Google Drive API error: %s
diff --git a/langs/fr_FR/googleapi.lang b/langs/fr_FR/googleapi.lang
index e4a97f2..fb42a53 100644
--- a/langs/fr_FR/googleapi.lang
+++ b/langs/fr_FR/googleapi.lang
@@ -47,3 +47,18 @@ GoogleApiOwnerEmail=Email Google du compte connecté
GoogleApiRemindByNotification=Rappel par notification Google
GoogleApiCalendarTZ=Timezone de l'agenda Google
GoogleApiIdId=Google ressource ID
+GoogleApiSendContexts = Contextes d'envoi
+GoogleApiEnabledContext = Contexte d'envoi %s
+GoogleApiDriveTab=Google Drive
+GoogleApiDriveNotConnected=Votre compte Google n'est pas encore connecté, ou le jeton d'accès a expiré.
+GoogleApiConnectDrive=Se connecter à Google Drive
+GoogleApiFolder=Dossier
+GoogleApiRename=Renommer
+GoogleApiNewName=Nouveau nom
+GoogleApiOpenInDrive=Ouvrir dans Drive
+GoogleApiConfirmDeleteDriveFile=Voulez-vous vraiment mettre "__FILENAME__" à la corbeille Google Drive ?
+GoogleApiUploadToThisFolder=Envoyer un fichier dans ce dossier
+GoogleApiDriveFileUploaded=Fichier envoyé sur Google Drive
+GoogleApiDriveFileRenamed=Renommé sur Google Drive
+GoogleApiDriveFileDeleted=Déplacé vers la corbeille Google Drive
+GoogleApiErrorDriveApi=Erreur API Google Drive : %s
diff --git a/lib/googleapi.lib.php b/lib/googleapi.lib.php
index d60ec8c..18e5675 100644
--- a/lib/googleapi.lib.php
+++ b/lib/googleapi.lib.php
@@ -68,15 +68,16 @@ function googleapiAdminPrepareHead()
/**
* Complete $object to change ->label and ->note before pushing event to Google Calendar.
*
- * @param Object $object Object event to complete
+ * @param ActionComm $object Object event to complete
* @param Translate $langs Language object
* @return void
*/
-function googleapi_complete_label_and_note(&$object, $langs)
+function googleapi_complete_label_and_note($object, $langs)
{
global $conf, $db, $langs;
global $dolibarr_main_url_root;
+ $langs->load('googleapi@googleapi');
$eventlabel = trim($object->label);
// Define $urlwithroot
$urlwithouturlroot = preg_replace('/' . preg_quote(DOL_URL_ROOT, '/') . '$/i', '', trim($dolibarr_main_url_root));
@@ -165,9 +166,9 @@ function getGoogleApiClient($fuser)
]);
$token = retrieveAccessToken('GoogleApi', $fuser->id);
- // Is token expired or will token expire in the next 30 seconds
+ // Is token expired or will token expire in the next 60 seconds
if (is_object($token)) {
- $expire = time() > ($token->getExpires() - 30);
+ $expire = time() > ($token->getExpires() - 60);
if ($expire) {
try {
// il faut sauvegarder le refresh token car google ne le donne qu'une seule fois
@@ -180,6 +181,8 @@ function getGoogleApiClient($fuser)
$token = $provider->getAccessToken($grant, ['refresh_token' => $refreshtoken]);
//$token->setRefreshToken($refreshtoken);
storeAccessToken('GoogleApi', $token, $refreshtoken, $fuser->id);
+ } catch (Throwable $t) {
+ dol_syslog($t->getMessage(), LOG_ERR);
} catch (Exception $e) {
dol_syslog($e->getMessage(), LOG_WARNING);
}
@@ -191,6 +194,32 @@ function getGoogleApiClient($fuser)
return $client;
}
+/**
+ * Get an authenticated Google Drive service for a user's connected Google account
+ *
+ * @param User $fuser User owning the Google OAuth token
+ * @return \Google\Service\Drive|false Drive service, or false if the user has no valid token
+ */
+function getGoogleDriveService($fuser)
+{
+ $client = getGoogleApiClient($fuser);
+ if (!is_object($client)) {
+ return false;
+ }
+ return new \Google\Service\Drive($client);
+}
+
+/**
+ * Escape a Google Drive object id for safe use inside a Drive API 'q' query string
+ *
+ * @param string $id Drive file or folder id
+ * @return string Escaped id
+ */
+function googleapiDriveEscapeId($id)
+{
+ return str_replace("'", "\\'", (string) $id);
+}
+
/**
* Create agenda event from task
*
diff --git a/notifications.php b/notifications.php
index 0093ede..61cf1c5 100644
--- a/notifications.php
+++ b/notifications.php
@@ -36,6 +36,7 @@
// Load Dolibarr environment
include 'config.php';
+require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php';
dol_include_once('/prune/vendor/autoload.php');
dol_include_once('/googleapi/lib/googleapi.lib.php');
@@ -203,8 +204,16 @@
$evt->context['googleapi'] = $db->escape($item->getId());
$res = $evt->update($fuser, 0);
if ($res < 0) {
- dol_syslog("googleapi notifications update actioncomm " . $evt->error, LOG_ERR);
+ dol_syslog("googleapi notifications update actioncomm FAILED " . $evt->error, LOG_ERR);
} else {
+ $evt->loadReminders('', 0, false);
+ foreach ($evt->reminders as $reminder) {
+ if ($reminder->status != 0) {
+ continue;
+ }
+ $reminder->dateremind = dol_time_plus_duree($evt->datep, -$reminder->offsetvalue, $reminder->offsetunit);
+ $reminder->update($fuser);
+ }
dol_syslog("googleapi notifications update actioncomm OK", LOG_NOTICE);
}
}
diff --git a/sql/update_0.0.0.-1.0.0.sql b/sql/update_0.0.0.-1.0.0.sql
index 23a4ed0..262a273 100644
--- a/sql/update_0.0.0.-1.0.0.sql
+++ b/sql/update_0.0.0.-1.0.0.sql
@@ -15,5 +15,5 @@
-- TO FIX PHP WARNINGS
UPDATE llx_extrafields SET enabled='isModEnabled("googleapi")' WHERE enabled='!empty($conf->googleapi->enabled)';
-UPDATE llx_extrafields set enabled = 'isModEnabled("googleapi")' WHERE enabled = '$conf->googleapi->enabled';
+UPDATE llx_extrafields SET enabled = 'isModEnabled("googleapi")' WHERE enabled = '$conf->googleapi->enabled';
UPDATE llx_c_actioncomm SET type='module', module='googleapi@googleapi' WHERE type='system' AND module='googleapi';
diff --git a/tabs/googleapi_emails.php b/tabs/googleapi_emails.php
index c44253c..8ade873 100644
--- a/tabs/googleapi_emails.php
+++ b/tabs/googleapi_emails.php
@@ -46,7 +46,7 @@
$toselect = GETPOST('toselect', 'array'); // Array of ids of elements selected into a list
$contextpage = GETPOST('contextpage', 'aZ') ? GETPOST('contextpage', 'aZ') : 'googleapilist'; // To manage different context of search
$backtopage = GETPOST('backtopage', 'alpha'); // Go back to a dedicated page
-$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print')
+$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print')
$id = (int) GETPOST('id', 'int');
// for member
diff --git a/tabs/usertoken.php b/tabs/usertoken.php
index 47b72b1..10a67bf 100644
--- a/tabs/usertoken.php
+++ b/tabs/usertoken.php
@@ -25,7 +25,10 @@
// Load Dolibarr environment
include '../config.php';
-
+/**
+ * @var Translate $langs
+ * @var string $dolibarr_main_url_root
+ */
require_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php';
require_once DOL_DOCUMENT_ROOT . '/core/lib/usergroups.lib.php';
require_once DOL_DOCUMENT_ROOT . '/user/class/user.class.php';
@@ -175,10 +178,10 @@
$refreshtoken = false;
$expiredat = '';
-// Is token expired or will token expire in the next 30 seconds
+// Is token expired or will token expire in the next 60 seconds
if (is_object($token)) {
$expire = $token->hasExpired();
- $isgoingtoexpire = (time() > ($token->getExpires() - 30));
+ $isgoingtoexpire = (time() > ($token->getExpires() - 60));
if ($isgoingtoexpire) {
$provider = new Google([
'clientId' => getDolGlobalString('OAUTH_GOOGLEAPI_ID'),
@@ -186,10 +189,17 @@
'redirectUri' => dol_buildpath('/googleapi/core/modules/oauth/googleapi_oauthcallback.php', 2),
]);
$grant = new RefreshToken();
- $token = $provider->getAccessToken($grant, ['refresh_token' => $tokenrefreshbackup]);
- $expire = $token->hasExpired();
- storeAccessToken('GoogleApi', $token, $tokenrefreshbackup, $object->id);
- setEventMessages($langs->trans('NewTokenStored'), null, 'mesgs'); // Stored into object managed by class DoliStorage so into table oauth_token
+ try {
+ $token = $provider->getAccessToken($grant, ['refresh_token' => $tokenrefreshbackup]);
+ $expire = $token->hasExpired();
+ storeAccessToken('GoogleApi', $token, $tokenrefreshbackup, $object->id);
+ setEventMessages($langs->trans('NewTokenStored'), null, 'mesgs'); // Stored into object managed by class DoliStorage so into table oauth_token
+ } catch (Throwable $t) {
+ dol_syslog($t->getMessage(), LOG_ERR);
+ } catch (Exception $e) {
+ dol_syslog($e->getMessage(), LOG_WARNING);
+ setEventMessage($e->getMessage());
+ }
}
$refreshtoken = $token->getRefreshToken();
@@ -309,9 +319,11 @@
// 'hostedDomain' => 'example.com', // optional; used to restrict access to users on your G Suite/Google Apps for Business accounts
'accessType' => 'offline',
]);
-
- $owner = $provider->getResourceOwner($token);
- // var_dump($owner->toArray());
+ try {
+ $owner = $provider->getResourceOwner($token);
+ } catch (Exception $e) {
+ setEventMessage($e->getMessage());
+ }
if (!empty($owner)) {
$object->array_options['options_googleapi_Id'] = $owner->getId();
$object->array_options['options_googleapi_email'] = $owner->toArray()['email'];