dolibarr 23.0.3
printgcp.modules.php
Go to the documentation of this file.
1<?php
2/*
3 * Copyright (C) 2014-2025 Frédéric France <frederic.france@free.fr>
4 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 * or see https://www.gnu.org/
19 */
20
27include_once DOL_DOCUMENT_ROOT.'/core/modules/printing/modules_printing.php';
28require_once DOL_DOCUMENT_ROOT.'/includes/OAuth/bootstrap.php';
29
30use OAuth\Common\Storage\DoliStorage;
31use OAuth\Common\Consumer\Credentials;
32
37{
41 public $name = 'printgcp';
42
46 public $desc = 'PrintGCPDesc';
47
51 public $picto = 'printer';
52
56 public $active = 'PRINTING_PRINTGCP';
57
61 public $conf = array();
62
66 public $google_id = '';
67
71 public $google_secret = '';
72
76 public $db;
77
81 private $OAUTH_SERVICENAME_GOOGLE = 'Google';
82
83 const LOGIN_URL = 'https://accounts.google.com/o/oauth2/token';
84 const PRINTERS_SEARCH_URL = 'https://www.google.com/cloudprint/search';
85 const PRINTERS_GET_JOBS = 'https://www.google.com/cloudprint/jobs';
86 const PRINT_URL = 'https://www.google.com/cloudprint/submit';
87
88
94 public function __construct($db)
95 {
96 global $conf, $langs, $dolibarr_main_url_root;
97
98 // Define $urlwithroot
99 $urlwithouturlroot = preg_replace('/'.preg_quote(DOL_URL_ROOT, '/').'$/i', '', trim($dolibarr_main_url_root));
100 $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
101 //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
102
103 $this->db = $db;
104
105 if (!isModEnabled('oauth')) {
106 $this->conf[] = array(
107 'varname' => 'PRINTGCP_INFO',
108 'info' => $langs->transnoentitiesnoconv("WarningModuleNotActive", "OAuth"),
109 'type' => 'info',
110 );
111 } else {
112 $keyforprovider = 'googleprint';
113
114 $this->google_id = getDolGlobalString('OAUTH_GOOGLE_ID');
115 $this->google_secret = getDolGlobalString('OAUTH_GOOGLE_SECRET');
116 // Token storage
117 $storage = new DoliStorage($this->db, $conf, $keyforprovider);
118
119 //$storage->clearToken($this->OAUTH_SERVICENAME_GOOGLE);
120 // Setup the credentials for the requests
121 $credentials = new Credentials(
122 $this->google_id,
123 $this->google_secret,
124 $urlwithroot.'/core/modules/oauth/google_oauthcallback.php'
125 );
126 $access = ($storage->hasAccessToken($this->OAUTH_SERVICENAME_GOOGLE) ? 'HasAccessToken' : 'NoAccessToken');
127
128 $serviceFactory = new \OAuth\ServiceFactory();
129 // Call $serviceFactory->buildV2Service() that do a construct with "new OAuth/OAuth2/Service/Google()" to build the $apiService object
130 $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array());
131 '@phan-var-force OAuth\OAuth2\Service\Google $apiService'; // createService is only ServiceInterface
132
133 $token_ok = true;
134 try {
135 // Do a select into oauth_token to get existing token
136 $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE);
137 } catch (Exception $e) {
138 $this->errors[] = $e->getMessage();
139 $token_ok = false;
140 }
141
142 $expire = false;
143 // Is token expired or will token expire in the next 30 seconds
144 if ($token_ok) {
145 $expire = ($token->getEndOfLife() !== -9002 && $token->getEndOfLife() !== -9001 && time() > ($token->getEndOfLife() - 30));
146 }
147
148 // Token expired so we refresh it
149 if ($token_ok && $expire) {
150 try {
151 // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois
152 $refreshtoken = $token->getRefreshToken();
153 $token = $apiService->refreshAccessToken($token);
154 $token->setRefreshToken($refreshtoken);
155 $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token);
156 } catch (Exception $e) {
157 $this->errors[] = $e->getMessage();
158 }
159 }
160 if ($this->google_id != '' && $this->google_secret != '') {
161 $this->conf[] = array(
162 'varname' => 'PRINTGCP_INFO',
163 'info' => 'GoogleAuthConfigured',
164 'type' => 'info'
165 );
166 $this->conf[] = array(
167 'varname' => 'PRINTGCP_TOKEN_ACCESS',
168 'info' => $access,
169 'type' => 'info',
170 'renew' => $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?state=userinfo_email,userinfo_profile,cloud_print&backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp'),
171 'delete' => ($storage->hasAccessToken($this->OAUTH_SERVICENAME_GOOGLE) ? $urlwithroot.'/core/modules/oauth/google_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp') : '')
172 );
173 if ($token_ok) {
174 $expiredat = '';
175
176 $refreshtoken = $token->getRefreshToken();
177
178 $endoflife = $token->getEndOfLife();
179
180 if ($endoflife == $token::EOL_NEVER_EXPIRES) {
181 $expiredat = $langs->trans("Never");
182 } elseif ($endoflife == $token::EOL_UNKNOWN) {
183 $expiredat = $langs->trans("Unknown");
184 } else {
185 $expiredat = dol_print_date($endoflife, "dayhour");
186 }
187
188 $this->conf[] = array('varname' => 'TOKEN_REFRESH', 'info' => ((!empty($refreshtoken)) ? 'Yes' : 'No'), 'type' => 'info');
189 $this->conf[] = array('varname' => 'TOKEN_EXPIRED', 'info' => ($expire ? 'Yes' : 'No'), 'type' => 'info');
190 $this->conf[] = array('varname' => 'TOKEN_EXPIRE_AT', 'info' => ($expiredat), 'type' => 'info');
191 }
192 /*
193 if ($storage->hasAccessToken($this->OAUTH_SERVICENAME_GOOGLE)) {
194 $this->conf[] = array('varname'=>'PRINTGCP_AUTHLINK', 'link'=>$urlwithroot.'/core/modules/oauth/google_oauthcallback.php?backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp'), 'type'=>'authlink');
195 $this->conf[] = array('varname'=>'DELETE_TOKEN', 'link'=>$urlwithroot.'/core/modules/oauth/google_oauthcallback.php?action=delete&token='.newToken().'&backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp'), 'type'=>'delete');
196 } else {
197 $this->conf[] = array('varname'=>'PRINTGCP_AUTHLINK', 'link'=>$urlwithroot.'/core/modules/oauth/google_oauthcallback.php?backtourl='.urlencode(DOL_URL_ROOT.'/printing/admin/printing.php?mode=setup&driver=printgcp'), 'type'=>'authlink');
198 }*/
199 } else {
200 $this->conf[] = array(
201 'varname' => 'PRINTGCP_INFO',
202 'info' => 'GoogleAuthNotConfigured',
203 'type' => 'info'
204 );
205 }
206 }
207 // do not display submit button
208 $this->conf[] = array('enabled' => 0, 'type' => 'submit');
209 }
210
216 public function listAvailablePrinters()
217 {
218 global $conf, $langs;
219 $error = 0;
220 $langs->load('printing');
221
222 $html = '<tr class="liste_titre">';
223 $html .= '<td>'.$langs->trans('GCP_Name').'</td>';
224 $html .= '<td>'.$langs->trans('GCP_displayName').'</td>';
225 $html .= '<td>'.$langs->trans('GCP_Id').'</td>';
226 $html .= '<td>'.$langs->trans('GCP_OwnerName').'</td>';
227 $html .= '<td>'.$langs->trans('GCP_State').'</td>';
228 $html .= '<td>'.$langs->trans('GCP_connectionStatus').'</td>';
229 $html .= '<td>'.$langs->trans('GCP_Type').'</td>';
230 $html .= '<td class="center">'.$langs->trans("Select").'</td>';
231 $html .= '</tr>'."\n";
232 $list = $this->getlistAvailableGcpPrinters();
233 //$html.= '<td><pre>'.print_r($list,true).'</pre></td>';
234 foreach ($list['available'] as $printer_det) {
235 $html .= '<tr class="oddeven">';
236 $html .= '<td>'.$printer_det['name'].'</td>';
237 $html .= '<td>'.$printer_det['displayName'].'</td>';
238 $html .= '<td>'.$printer_det['id'].'</td>'; // id to identify printer to use
239 $html .= '<td>'.$printer_det['ownerName'].'</td>';
240 $html .= '<td>'.$printer_det['status'].'</td>';
241 $html .= '<td>'.$langs->trans('STATE_'.$printer_det['connectionStatus']).'</td>';
242 $html .= '<td>'.$langs->trans('TYPE_'.$printer_det['type']).'</td>';
243 // Default
244 $html .= '<td class="center">';
245 if (getDolGlobalString('PRINTING_GCP_DEFAULT') == $printer_det['id']) {
246 $html .= img_picto($langs->trans("Default"), 'on');
247 } else {
248 $html .= '<a href="'.$_SERVER["PHP_SELF"].'?action=setvalue&token='.newToken().'&mode=test&varname=PRINTING_GCP_DEFAULT&driver=printgcp&value='.urlencode($printer_det['id']).'" alt="'.$langs->trans("Default").'">'.img_picto($langs->trans("Disabled"), 'off').'</a>';
249 }
250 $html .= '</td>';
251 $html .= '</tr>'."\n";
252 }
253 $this->resprint = $html;
254 return $error;
255 }
256
257
263 public function getlistAvailablePrinters()
264 {
265 /* Compatible with paretn class signature */
266 return $this->getlistAvailableGcpPrinters()['available'];
267 }
268
269
276 {
277 global $conf;
278 $ret = array();
279
280 $keyforprovider = 'googleprint';
281
282 // Token storage
283 $storage = new DoliStorage($this->db, $conf, $keyforprovider);
284 // Setup the credentials for the requests
285 $credentials = new Credentials(
286 $this->google_id,
287 $this->google_secret,
288 DOL_MAIN_URL_ROOT.'/core/modules/oauth/google_oauthcallback.php'
289 );
290 $serviceFactory = new \OAuth\ServiceFactory();
291 $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array());
292 '@phan-var-force OAuth\OAuth2\Service\Google $apiService'; // createService is only ServiceInterface
293 // Check if we have auth token
294 $token_ok = true;
295 try {
296 $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE);
297 } catch (Exception $e) {
298 $this->errors[] = $e->getMessage();
299 $token_ok = false;
300 }
301 $expire = false;
302 // Is token expired or will token expire in the next 30 seconds
303 if ($token_ok) {
304 $expire = ($token->getEndOfLife() !== -9002 && $token->getEndOfLife() !== -9001 && time() > ($token->getEndOfLife() - 30));
305 }
306
307 // Token expired so we refresh it
308 if ($token_ok && $expire) {
309 try {
310 // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois
311 $refreshtoken = $token->getRefreshToken();
312 $token = $apiService->refreshAccessToken($token);
313 $token->setRefreshToken($refreshtoken);
314 $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token);
315 } catch (Exception $e) {
316 $this->errors[] = $e->getMessage();
317 }
318 }
319 // Send a request with api
320 try {
321 $response = $apiService->request(self::PRINTERS_SEARCH_URL);
322 } catch (Exception $e) {
323 $this->errors[] = $e->getMessage();
324 print '<pre>'.print_r($e->getMessage(), true).'</pre>';
325 }
326 //print '<tr><td><pre>'.print_r($response, true).'</pre></td></tr>';
327 $responsedata = json_decode($response, true);
328 $printers = $responsedata['printers'];
329 // Check if we have printers?
330 if (is_array($printers) && count($printers) == 0) {
331 // We don't have printers so return blank array
332 $ret['available'] = array();
333 } else {
334 // We have printers so returns printers as array
335 $ret['available'] = $printers;
336 }
337 return $ret;
338 }
339
348 public function printFile($file, $module, $subdir = '')
349 {
350 require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
351
352 global $conf, $user;
353 $error = 0;
354
355 $fileprint = $conf->{$module}->dir_output;
356 if ($subdir != '') {
357 $fileprint .= '/'.$subdir;
358 }
359 $fileprint .= '/'.$file;
360 $mimetype = dol_mimetype($fileprint);
361 $printer_id = '';
362 // select printer uri for module order, propal,...
363 $sql = "SELECT rowid, printer_id, copy FROM ".MAIN_DB_PREFIX."printing WHERE module='".$this->db->escape($module)."' AND driver='printgcp' AND userid=".((int) $user->id);
364 $result = $this->db->query($sql);
365 if ($result) {
366 $obj = $this->db->fetch_object($result);
367 if ($obj) {
368 $printer_id = $obj->printer_id;
369 } else {
370 if (getDolGlobalString('PRINTING_GCP_DEFAULT')) {
371 $printer_id = getDolGlobalString('PRINTING_GCP_DEFAULT');
372 } else {
373 $this->errors[] = 'NoDefaultPrinterDefined';
374 $error++;
375 return $error;
376 }
377 }
378 } else {
379 dol_print_error($this->db);
380 }
381
382 $ret = $this->sendPrintToPrinter($printer_id, $file, $fileprint, $mimetype);
383 $this->error = 'PRINTGCP: '.$ret['errormessage'];
384 if ($ret['status'] != 1) {
385 $error++;
386 }
387 return $error;
388 }
389
399 public function sendPrintToPrinter($printerid, $printjobtitle, $filepath, $contenttype)
400 {
401 global $conf;
402 // Check if printer id
403 if (empty($printerid)) {
404 return array('status' => 0, 'errorcode' => '', 'errormessage' => 'No provided printer ID');
405 }
406 // Open the file which needs to be print
407 $handle = fopen($filepath, "rb");
408 if (!$handle) {
409 return array('status' => 0, 'errorcode' => '', 'errormessage' => 'Could not read the file.');
410 }
411 // Read file content
412 $contents = fread($handle, filesize($filepath));
413 fclose($handle);
414 // Prepare post fields for sending print
415 $post_fields = array(
416 'printerid' => $printerid,
417 'title' => $printjobtitle,
418 'contentTransferEncoding' => 'base64',
419 'content' => base64_encode($contents), // encode file content as base64
420 'contentType' => $contenttype,
421 );
422
423 $keyforprovider = 'googleprint';
424
425 // Dolibarr Token storage
426 $storage = new DoliStorage($this->db, $conf, $keyforprovider);
427 // Setup the credentials for the requests
428 $credentials = new Credentials(
429 $this->google_id,
430 $this->google_secret,
431 DOL_MAIN_URL_ROOT.'/core/modules/oauth/google_oauthcallback.php?service=google'
432 );
433 $serviceFactory = new \OAuth\ServiceFactory();
434 $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array());
435 '@phan-var-force OAuth\OAuth2\Service\Google $apiService'; // createService is only ServiceInterface
436
437 // Check if we have auth token and refresh it
438 $token_ok = true;
439 try {
440 $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE);
441 } catch (Exception $e) {
442 $this->errors[] = $e->getMessage();
443 $token_ok = false;
444 }
445 if ($token_ok) {
446 try {
447 // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois
448 $refreshtoken = $token->getRefreshToken();
449 $token = $apiService->refreshAccessToken($token);
450 $token->setRefreshToken($refreshtoken);
451 $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token);
452 } catch (Exception $e) {
453 $this->errors[] = $e->getMessage();
454 }
455 }
456
457 // Send a request with api
458 $response = json_decode($apiService->request(self::PRINT_URL, 'POST', $post_fields), true);
459 //print '<tr><td><pre>'.print_r($response, true).'</pre></td></tr>';
460 return array('status' => $response['success'], 'errorcode' => $response['errorCode'], 'errormessage' => $response['message']);
461 }
462
463
471 public function listJobs($module = null)
472 {
473 global $conf, $langs;
474
475 $error = 0;
476 $html = '';
477
478 $keyforprovider = 'googleprint';
479
480 // Token storage
481 $storage = new DoliStorage($this->db, $conf, $keyforprovider);
482 // Setup the credentials for the requests
483 $credentials = new Credentials(
484 $this->google_id,
485 $this->google_secret,
486 DOL_MAIN_URL_ROOT.'/core/modules/oauth/google_oauthcallback.php'
487 );
488 $serviceFactory = new \OAuth\ServiceFactory();
489 $apiService = $serviceFactory->createService($this->OAUTH_SERVICENAME_GOOGLE, $credentials, $storage, array());
490 '@phan-var-force OAuth\OAuth2\Service\Google $apiService'; // createService is only ServiceInterface
491 // Check if we have auth token
492 $token_ok = true;
493 try {
494 $token = $storage->retrieveAccessToken($this->OAUTH_SERVICENAME_GOOGLE);
495 } catch (Exception $e) {
496 $this->errors[] = $e->getMessage();
497 $token_ok = false;
498 $error++;
499 }
500 $expire = false;
501 // Is token expired or will token expire in the next 30 seconds
502 if ($token_ok) {
503 $expire = ($token->getEndOfLife() !== -9002 && $token->getEndOfLife() !== -9001 && time() > ($token->getEndOfLife() - 30));
504 }
505
506 // Token expired so we refresh it
507 if ($token_ok && $expire) {
508 try {
509 // il faut sauvegarder le refresh token car google ne le donne qu'une seule fois
510 $refreshtoken = $token->getRefreshToken();
511 $token = $apiService->refreshAccessToken($token);
512 $token->setRefreshToken($refreshtoken);
513 $storage->storeAccessToken($this->OAUTH_SERVICENAME_GOOGLE, $token);
514 } catch (Exception $e) {
515 $this->errors[] = $e->getMessage();
516 $error++;
517 }
518 }
519 // Getting Jobs
520 // Send a request with api
521 try {
522 $response = $apiService->request(self::PRINTERS_GET_JOBS);
523 } catch (Exception $e) {
524 $this->errors[] = $e->getMessage();
525 $error++;
526 }
527 $responsedata = json_decode($response, true);
528 //$html .= '<pre>'.print_r($responsedata,true).'</pre>';
529 $html .= '<div class="div-table-responsive">';
530 $html .= '<table width="100%" class="noborder">';
531 $html .= '<tr class="liste_titre">';
532 $html .= '<td>'.$langs->trans("Id").'</td>';
533 $html .= '<td>'.$langs->trans("Date").'</td>';
534 $html .= '<td>'.$langs->trans("Owner").'</td>';
535 $html .= '<td>'.$langs->trans("Printer").'</td>';
536 $html .= '<td>'.$langs->trans("Filename").'</td>';
537 $html .= '<td>'.$langs->trans("Status").'</td>';
538 $html .= '<td>'.$langs->trans("Cancel").'</td>';
539 $html .= '</tr>'."\n";
540
541 $jobs = $responsedata['jobs'];
542 //$html .= '<pre>'.print_r($jobs['0'],true).'</pre>';
543 if (is_array($jobs)) {
544 foreach ($jobs as $value) {
545 $html .= '<tr class="oddeven">';
546 $html .= '<td>'.$value['id'].'</td>';
547 $dates = dol_print_date((int) substr($value['createTime'], 0, 10), 'dayhour');
548 $html .= '<td>'.$dates.'</td>';
549 $html .= '<td>'.$value['ownerId'].'</td>';
550 $html .= '<td>'.$value['printerName'].'</td>';
551 $html .= '<td>'.$value['title'].'</td>';
552 $html .= '<td>'.$value['status'].'</td>';
553 $html .= '<td>&nbsp;</td>';
554 $html .= '</tr>';
555 }
556 } else {
557 $html .= '<tr class="oddeven">';
558 $html .= '<td colspan="7" class="opacitymedium">'.$langs->trans("None").'</td>';
559 $html .= '</tr>';
560 }
561 $html .= '</table>';
562 $html .= '</div>';
563
564 $this->resprint = $html;
565
566 return $error;
567 }
568}
global $dolibarr_main_url_root
Parent class of emailing target selectors modules.
Class to provide printing with Google Cloud Print.
listJobs($module=null)
List jobs print.
__construct($db)
Constructor.
listAvailablePrinters()
Return list of available printers.
printFile($file, $module, $subdir='')
Print selected file.
getlistAvailablePrinters()
Return list of available printers.
sendPrintToPrinter($printerid, $printjobtitle, $filepath, $contenttype)
Sends document to the printer.
getlistAvailableGcpPrinters()
Return list of available printers (internal format)
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dol_mimetype($file, $default='application/octet-stream', $mode=0)
Return MIME type of a file from its name with extension.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
conf($dolibarr_main_document_root)
Load conf file (file must exists)
Definition inc.php:426