6 | *
7 | * This program is free software; you can redistribute it and/or modify
8 | * it under the terms of the GNU General Public License as published by
9 | * the Free Software Foundation; either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This program is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU General Public License
18 | * along with this program. If not, see .
19 | */
20 |
21 | /**
22 | * \defgroup cdav Module CDav
23 | * \brief allows caldav and carddav clients to sync with Dolibarr.
24 | * \file htdocs/cdav/core/modules/modCDav.class.php
25 | * \ingroup cdav
26 | * \brief Description and activation file for module CDav
27 | */
28 | include_once DOL_DOCUMENT_ROOT .'/core/modules/DolibarrModules.class.php';
29 |
30 |
31 | /**
32 | * Description and activation class for module CDav
33 | */
34 | class modCDav extends DolibarrModules
35 | {
36 | /**
37 | * Constructor. Define names, constants, directories, boxes, permissions
38 | *
39 | * @param DoliDB $db Database handler
40 | */
41 | function __construct($db)
42 | {
43 | global $langs,$conf;
44 |
45 | $this->db = $db;
46 |
47 | // Id for module (must be unique).
48 | // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
49 | $this->numero = 562387;
50 | // Key text used to identify module (for permissions, menus, etc...)
51 | $this->rights_class = 'cdav';
52 |
53 | // Family can be 'crm','financial','hr','projects','products','ecm','technic','other'
54 | // It is used to group modules in module setup page
55 | $this->family = "technic";
56 | // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
57 | $this->name = preg_replace('/^mod/i','',get_class($this));
58 | // Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module)
59 | $this->description = "Allows caldav and carddav clients to sync with Dolibarr.";
60 | // Possible values for version are: 'development', 'experimental', 'dolibarr' or version
61 | $this->version = '3.1.1';
62 | // Key used in llx_const table to save module status enabled/disabled (where CDAV is value of property name of module in uppercase)
63 | $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
64 | // Where to store the module in setup page (0=common,1=interface,2=others,3=very specific)
65 | $this->special = 1;
66 | // Name of image file used for this module.
67 | // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
68 | // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
69 | $this->picto='technic';
70 |
71 | // Defined all module parts (triggers, login, substitutions, menus, css, etc...)
72 | // for default path (eg: /mymodule/core/xxxxx) (0=disable, 1=enable)
73 | // for specific path of parts (eg: /mymodule/core/modules/barcode)
74 | // for specific css file (eg: /mymodule/css/mymodule.css.php)
75 | //$this->module_parts = array(
76 | // 'triggers' => 0, // Set this to 1 if module has its own trigger directory (core/triggers)
77 | // 'login' => 0, // Set this to 1 if module has its own login method directory (core/login)
78 | // 'substitutions' => 0, // Set this to 1 if module has its own substitution function file (core/substitutions)
79 | // 'menus' => 0, // Set this to 1 if module has its own menus handler directory (core/menus)
80 | // 'theme' => 0, // Set this to 1 if module has its own theme directory (theme)
81 | // 'tpl' => 0, // Set this to 1 if module overwrite template dir (core/tpl)
82 | // 'barcode' => 0, // Set this to 1 if module has its own barcode directory (core/modules/barcode)
83 | // 'models' => 0, // Set this to 1 if module has its own models directory (core/modules/xxx)
84 | // 'css' => array('/mymodule/css/mymodule.css.php'), // Set this to relative path of css file if module has its own css file
85 | // 'js' => array('/mymodule/js/mymodule.js'), // Set this to relative path of js file if module must load a js on all pages
86 | // 'hooks' => array('hookcontext1','hookcontext2') // Set here all hooks context managed by module
87 | // 'dir' => array('output' => 'othermodulename'), // To force the default directories names
88 | // 'workflow' => array('WORKFLOW_MODULE1_YOURACTIONTYPE_MODULE2'=>array('enabled'=>'! empty($conf->module1->enabled) && ! empty($conf->module2->enabled)', 'picto'=>'yourpicto@mymodule')) // Set here all workflow context managed by module
89 | // );
90 | $this->module_parts = array(
91 | 'hooks' => array('projectcard', 'projecttaskscard'),
92 | );
93 |
94 | // Data directories to create when module is enabled.
95 | // Example: this->dirs = array("/mymodule/temp");
96 | $this->dirs = array('/cdav','/cdav/public');
97 |
98 | // Config pages. Put here list of php page, stored into mymodule/admin directory, to use to setup module.
99 | $this->config_page_url = array('setup.php@cdav');
100 |
101 | // Dependencies
102 | $this->hidden = false; // A condition to hide module
103 | $this->depends = array(); // List of modules id that must be enabled if this module is enabled
104 | $this->requiredby = array(); // List of modules id to disable if this one is disabled
105 | $this->conflictwith = array(); // List of modules id this module is in conflict with
106 | $this->phpmin = array(5,6); // Minimum version of PHP required by module
107 | $this->need_dolibarr_version = array(7,0); // Minimum version of Dolibarr required by module
108 | $this->langfiles = array();
109 |
110 | // Constants
111 | // List of particular constants to add when module is enabled (key, 'chaine', value, desc, visible, 'current' or 'allentities', deleteonunactive)
112 | // Example: $this->const=array(0=>array('MYMODULE_MYNEWCONST1','chaine','myvalue','This is a constant to add',1),
113 | // 1=>array('MYMODULE_MYNEWCONST2','chaine','myvalue','This is another constant to add',0, 'current', 1)
114 | // );
115 | $this->const = array(
116 | 0 => array('CDAV_URI_KEY', 'chaine', substr(md5(time()),0,8),'Change it to force client to resync',0,'current',0),
117 | 1 => array('CDAV_CONTACT_TAG', 'chaine', '', 'Contact tag to restrict contacts to sync, leave blank for all',0,'current',0),
118 | 2 => array('CDAV_THIRD_SYNC', 'chaine', '0', 'How to sync thirdparties',0,'current',0),
119 | 3 => array('CDAV_SYNC_PAST', 'chaine', '31', 'Number of days to sync before today',0,'current',0),
120 | 4 => array('CDAV_SYNC_FUTURE', 'chaine', '365', 'Number of days to sync after today',0,'current',0),
121 | 5 => array('CDAV_TASK_SYNC', 'chaine', '0', 'How to sync project tasks',0,'current',0),
122 | 6 => array('CDAV_GENTASK', 'chaine', '0', 'Convert documents to tasks',0,'current',0),
123 | 7 => array('CDAV_GENTASK_INI1', 'chaine', '0', 'Generate initial tasks from services',0,'current',0),
124 | 8 => array('CDAV_GENTASK_INI2', 'chaine', '0', 'Generate initial tasks from services',0,'current',0),
125 | 9 => array('CDAV_GENTASK_INI3', 'chaine', '0', 'Generate initial tasks from services',0,'current',0),
126 | 10 => array('CDAV_GENTASK_END1', 'chaine', '0', 'Generate final tasks from services',0,'current',0),
127 | 11 => array('CDAV_GENTASK_END2', 'chaine', '0', 'Generate final tasks from services',0,'current',0),
128 | 12 => array('CDAV_GENTASK_END3', 'chaine', '0', 'Generate final tasks from services',0,'current',0),
129 | 13 => array('CDAV_PROJ_USER_ROLE', 'chaine', '', 'Project user role to find default task owner',0,'current',0),
130 | 14 => array('CDAV_TASK_USER_ROLE', 'chaine', '', 'Project task user role when creating a new project task',0,'current',0),
131 | 15 => array('CDAV_GENTASK_SERVICE_TAG', 'chaine', '', 'Service tag to restrict services to be converted as task, leave blank to sync all',0,'current',0),
132 | 16 => array('CDAV_EXTRAFIELD_DURATION', 'chaine', '', 'Duration services',0,'current',0),
133 | 17 => array('CDAV_TASK_HOUR_INI', 'chaine', '', 'Begining of a working day',0,'current',0),
134 | 18 => array('CDAV_TASK_HOUR_END', 'chaine', '', 'Ending of a working day',0,'current',0),
135 | 19 => array('CDAV_QRCODE_DAVX5_ENABLED', 'chaine', '0', 'Activate DavX5 auto URL',0,'current',0),
136 | 20 => array('CDAV_MEMBER_SYNC', 'chaine', '0', 'Sync members',0,'current',0),
137 | );
138 |
139 | // Array to add new pages in new tabs
140 | // Example: $this->tabs = array('objecttype:+tabname1:Title1:mylangfile@mymodule:$user->rights->mymodule->read:/mymodule/mynewtab1.php?id=__ID__', // To add a new tab identified by code tabname1
141 | // 'objecttype:+tabname2:SUBSTITUTION_Title2:mylangfile@mymodule:$user->rights->othermodule->read:/mymodule/mynewtab2.php?id=__ID__', // To add another new tab identified by code tabname2. Label will be result of calling all substitution functions on 'Title2' key.
142 | // 'objecttype:-tabname:NU:conditiontoremove'); // To remove an existing tab identified by code tabname
143 | // where objecttype can be
144 | // 'categories_x' to add a tab in category view (replace 'x' by type of category (0=product, 1=supplier, 2=customer, 3=member)
145 | // 'contact' to add a tab in contact view
146 | // 'contract' to add a tab in contract view
147 | // 'group' to add a tab in group view
148 | // 'intervention' to add a tab in intervention view
149 | // 'invoice' to add a tab in customer invoice view
150 | // 'invoice_supplier' to add a tab in supplier invoice view
151 | // 'member' to add a tab in fundation member view
152 | // 'opensurveypoll' to add a tab in opensurvey poll view
153 | // 'order' to add a tab in customer order view
154 | // 'order_supplier' to add a tab in supplier order view
155 | // 'payment' to add a tab in payment view
156 | // 'payment_supplier' to add a tab in supplier payment view
157 | // 'product' to add a tab in product view
158 | // 'propal' to add a tab in propal view
159 | // 'project' to add a tab in project view
160 | // 'stock' to add a tab in stock view
161 | // 'thirdparty' to add a tab in third party view
162 | // 'user' to add a tab in user view
163 | $this->tabs = array();
164 |
165 | // Dictionaries
166 | if (! isset($conf->cdav->enabled))
167 | {
168 | $conf->cdav=new stdClass();
169 | $conf->cdav->enabled=0;
170 | }
171 | $this->dictionaries=array();
172 | /* Example:
173 | if (! isset($conf->mymodule->enabled)) $conf->mymodule->enabled=0; // This is to avoid warnings
174 | $this->dictionaries=array(
175 | 'langs'=>'mylangfile@mymodule',
176 | 'tabname'=>array(MAIN_DB_PREFIX."table1",MAIN_DB_PREFIX."table2",MAIN_DB_PREFIX."table3"), // List of tables we want to see into dictonnary editor
177 | 'tablib'=>array("Table1","Table2","Table3"), // Label of tables
178 | 'tabsql'=>array('SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table1 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table2 as f','SELECT f.rowid as rowid, f.code, f.label, f.active FROM '.MAIN_DB_PREFIX.'table3 as f'), // Request to select fields
179 | 'tabsqlsort'=>array("label ASC","label ASC","label ASC"), // Sort order
180 | 'tabfield'=>array("code,label","code,label","code,label"), // List of fields (result of select to show dictionary)
181 | 'tabfieldvalue'=>array("code,label","code,label","code,label"), // List of fields (list of fields to edit a record)
182 | 'tabfieldinsert'=>array("code,label","code,label","code,label"), // List of fields (list of fields for insert)
183 | 'tabrowid'=>array("rowid","rowid","rowid"), // Name of columns with primary key (try to always name it 'rowid')
184 | 'tabcond'=>array($conf->mymodule->enabled,$conf->mymodule->enabled,$conf->mymodule->enabled) // Condition to show each dictionary
185 | );
186 | */
187 |
188 | // Boxes
189 | // Add here list of php file(s) stored in core/boxes that contains class to show a box.
190 | $this->boxes = array(); // List of boxes
191 | // Example:
192 | //$this->boxes=array(array(0=>array('file'=>'myboxa.php','note'=>'','enabledbydefaulton'=>'Home'),1=>array('file'=>'myboxb.php','note'=>''),2=>array('file'=>'myboxc.php','note'=>'')););
193 |
194 | // Permissions
195 | $this->rights = array(); // Permission array used by this module
196 | $r=0;
197 |
198 | // Add here list of permission defined by an id, a label, a boolean and two constant strings.
199 | // Example:
200 | // $this->rights[$r][0] = $this->numero + $r; // Permission id (must not be already used)
201 | // $this->rights[$r][1] = 'Permision label'; // Permission label
202 | // $this->rights[$r][3] = 1; // Permission by default for new user (0/1)
203 | // $this->rights[$r][4] = 'level1'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2)
204 | // $this->rights[$r][5] = 'level2'; // In php code, permission will be checked by test if ($user->rights->permkey->level1->level2)
205 | // $r++;
206 |
207 |
208 | // Main menu entries
209 | $this->menu = array(); // List of menus to add
210 | $r=0;
211 |
212 | $this->menu[$r++] = array( 'fk_menu'=>'fk_mainmenu=companies,fk_leftmenu=contacts', // Put 0 if this is a top menu
213 | 'type'=>'left', // This is a Top menu entry
214 | 'titre'=>'CardDAVurl',
215 | 'mainmenu'=>'companies',
216 | 'leftmenu'=>'contacts',
217 | 'url'=>'/cdav/cdavurls.php?type=CardDAV&leftmenu=contacts',
218 | 'langs'=>'cdav@cdav', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
219 | 'position'=>190,
220 | 'enabled'=>'$conf->cdav->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled.
221 | 'perms'=>'$user->rights->societe->contact->lire', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules
222 | 'target'=>'',
223 | 'user'=>0);
224 |
225 | $this->menu[$r++] = array( 'fk_menu'=>'fk_mainmenu=agenda', // Put 0 if this is a top menu
226 | 'type'=>'left', // This is a Top menu entry
227 | 'titre'=>'CalDAVurl',
228 | 'mainmenu'=>'agenda',
229 | 'url'=>'/cdav/cdavurls.php?type=CalDAV&mainmenu=agenda',
230 | 'langs'=>'cdav@cdav', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
231 | 'position'=>190,
232 | 'enabled'=>'$conf->cdav->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled.
233 | 'perms'=>'$user->rights->agenda->myactions->read', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules
234 | 'target'=>'',
235 | 'user'=>0);
236 |
237 | $this->menu[$r++] = array( 'fk_menu'=>'fk_mainmenu=agenda', // Put 0 if this is a top menu
238 | 'type'=>'left', // This is a Top menu entry
239 | 'titre'=>'ICSurl',
240 | 'mainmenu'=>'agenda',
241 | 'url'=>'/cdav/cdavurls.php?type=ICS&mainmenu=agenda',
242 | 'langs'=>'cdav@cdav', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
243 | 'position'=>190,
244 | 'enabled'=>'$conf->cdav->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled.
245 | 'perms'=>'$user->rights->agenda->myactions->read', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules
246 | 'target'=>'',
247 | 'user'=>0);
248 | // Add here entries to declare new menus
249 | //
250 | // Example to declare a new Top Menu entry and its Left menu entry:
251 | // $this->menu[$r]=array( 'fk_menu'=>0, // Put 0 if this is a top menu
252 | // 'type'=>'top', // This is a Top menu entry
253 | // 'titre'=>'MyModule top menu',
254 | // 'mainmenu'=>'mymodule',
255 | // 'leftmenu'=>'mymodule',
256 | // 'url'=>'/mymodule/pagetop.php',
257 | // 'langs'=>'mylangfile@mymodule', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
258 | // 'position'=>100,
259 | // 'enabled'=>'$conf->mymodule->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled.
260 | // 'perms'=>'1', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules
261 | // 'target'=>'',
262 | // 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both
263 | // $r++;
264 | //
265 | // Example to declare a Left Menu entry into an existing Top menu entry:
266 | // $this->menu[$r]=array( 'fk_menu'=>'fk_mainmenu=xxx', // Use 'fk_mainmenu=xxx' or 'fk_mainmenu=xxx,fk_leftmenu=yyy' where xxx is mainmenucode and yyy is a leftmenucode
267 | // 'type'=>'left', // This is a Left menu entry
268 | // 'titre'=>'MyModule left menu',
269 | // 'mainmenu'=>'xxx',
270 | // 'leftmenu'=>'mymodule',
271 | // 'url'=>'/mymodule/pagelevel2.php',
272 | // 'langs'=>'mylangfile@mymodule', // Lang file to use (without .lang) by module. File must be in langs/code_CODE/ directory.
273 | // 'position'=>100,
274 | // 'enabled'=>'$conf->mymodule->enabled', // Define condition to show or hide menu entry. Use '$conf->mymodule->enabled' if entry must be visible if module is enabled. Use '$leftmenu==\'system\'' to show if leftmenu system is selected.
275 | // 'perms'=>'1', // Use 'perms'=>'$user->rights->mymodule->level1->level2' if you want your menu with a permission rules
276 | // 'target'=>'',
277 | // 'user'=>2); // 0=Menu for internal users, 1=external users, 2=both
278 | // $r++;
279 |
280 |
281 | // Exports
282 | $r=1;
283 |
284 | // Example:
285 | // $this->export_code[$r]=$this->rights_class.'_'.$r;
286 | // $this->export_label[$r]='CustomersInvoicesAndInvoiceLines'; // Translation key (used only if key ExportDataset_xxx_z not found)
287 | // $this->export_enabled[$r]='1'; // Condition to show export in list (ie: '$user->id==3'). Set to 1 to always show when module is enabled.
288 | // $this->export_permission[$r]=array(array("facture","facture","export"));
289 | // $this->export_fields_array[$r]=array('s.rowid'=>"IdCompany",'s.nom'=>'CompanyName','s.address'=>'Address','s.zip'=>'Zip','s.town'=>'Town','s.fk_pays'=>'Country','s.phone'=>'Phone','s.siren'=>'ProfId1','s.siret'=>'ProfId2','s.ape'=>'ProfId3','s.idprof4'=>'ProfId4','s.code_compta'=>'CustomerAccountancyCode','s.code_compta_fournisseur'=>'SupplierAccountancyCode','f.rowid'=>"InvoiceId",'f.facnumber'=>"InvoiceRef",'f.datec'=>"InvoiceDateCreation",'f.datef'=>"DateInvoice",'f.total'=>"TotalHT",'f.total_ttc'=>"TotalTTC",'f.tva'=>"TotalVAT",'f.paye'=>"InvoicePaid",'f.fk_statut'=>'InvoiceStatus','f.note'=>"InvoiceNote",'fd.rowid'=>'LineId','fd.description'=>"LineDescription",'fd.price'=>"LineUnitPrice",'fd.tva_tx'=>"LineVATRate",'fd.qty'=>"LineQty",'fd.total_ht'=>"LineTotalHT",'fd.total_tva'=>"LineTotalTVA",'fd.total_ttc'=>"LineTotalTTC",'fd.date_start'=>"DateStart",'fd.date_end'=>"DateEnd",'fd.fk_product'=>'ProductId','p.ref'=>'ProductRef');
290 | // $this->export_entities_array[$r]=array('s.rowid'=>"company",'s.nom'=>'company','s.address'=>'company','s.zip'=>'company','s.town'=>'company','s.fk_pays'=>'company','s.phone'=>'company','s.siren'=>'company','s.siret'=>'company','s.ape'=>'company','s.idprof4'=>'company','s.code_compta'=>'company','s.code_compta_fournisseur'=>'company','f.rowid'=>"invoice",'f.facnumber'=>"invoice",'f.datec'=>"invoice",'f.datef'=>"invoice",'f.total'=>"invoice",'f.total_ttc'=>"invoice",'f.tva'=>"invoice",'f.paye'=>"invoice",'f.fk_statut'=>'invoice','f.note'=>"invoice",'fd.rowid'=>'invoice_line','fd.description'=>"invoice_line",'fd.price'=>"invoice_line",'fd.total_ht'=>"invoice_line",'fd.total_tva'=>"invoice_line",'fd.total_ttc'=>"invoice_line",'fd.tva_tx'=>"invoice_line",'fd.qty'=>"invoice_line",'fd.date_start'=>"invoice_line",'fd.date_end'=>"invoice_line",'fd.fk_product'=>'product','p.ref'=>'product');
291 | // $this->export_sql_start[$r]='SELECT DISTINCT ';
292 | // $this->export_sql_end[$r] =' FROM ('.MAIN_DB_PREFIX.'facture as f, '.MAIN_DB_PREFIX.'facturedet as fd, '.MAIN_DB_PREFIX.'societe as s)';
293 | // $this->export_sql_end[$r] .=' LEFT JOIN '.MAIN_DB_PREFIX.'product as p on (fd.fk_product = p.rowid)';
294 | // $this->export_sql_end[$r] .=' WHERE f.fk_soc = s.rowid AND f.rowid = fd.fk_facture';
295 | // $this->export_sql_order[$r] .=' ORDER BY s.nom';
296 | // $r++;
297 | }
298 |
299 | /**
300 | * Function called when module is enabled.
301 | * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database.
302 | * It also creates data directories
303 | *
304 | * @param string $options Options when enabling module ('', 'noboxes')
305 | * @return int 1 if OK, 0 if KO
306 | */
307 | function init($options='')
308 | {
309 | global $langs;
310 | $sql = array();
311 |
312 | // Create 2 extrafields
313 | include_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
314 | $extrafields_cmd = new ExtraFields($this->db);
315 |
316 | try
317 | {
318 | //function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique=0, $required=0, $default_value='', $param='', $alwayseditable=0, $perms='', $list='-1', $help='', $computed='', $entity='', $langfile='', $enabled='1')
319 | $result_cmd=$extrafields_cmd->addExtraField('cdav_duration', $langs->trans("DurationEx"), 'varchar', 1, '10', 'commandedet', 0, 0, '', '', 1, '', '1');
320 | if( ! $result_cmd )
321 | {
322 | $this->error=$extrafields_cmd->error;
323 | }
324 | $extrafields_prop = new ExtraFields($this->db);
325 | $result_prop=$extrafields_prop->addExtraField('cdav_duration', $langs->trans("DurationEx"), 'varchar', 1, '10', 'propaldet', 0, 0, '', '', 1, '', '1');
326 | if( ! $result_prop )
327 | {
328 | $this->error=$extrafields_prop->error;
329 | }
330 |
331 | $result=$this->_load_tables('/cdav/sql/');
332 | }
333 | catch(Exception $ex)
334 | {
335 | $this->error = $ex->getMessage();
336 | }
337 |
338 | return $this->_init($sql, $options);
339 | }
340 |
341 | /**
342 | * Function called when module is disabled.
343 | * Remove from database constants, boxes and permissions from Dolibarr database.
344 | * Data directories are not deleted
345 | *
346 | * @param string $options Options when enabling module ('', 'noboxes')
347 | * @return int 1 if OK, 0 if KO
348 | */
349 | function remove($options='')
350 | {
351 | $sql = array();
352 |
353 | return $this->_remove($sql, $options);
354 | }
355 |
356 | }
357 |
358 |
--------------------------------------------------------------------------------
/doc/description_en.html:
--------------------------------------------------------------------------------
1 | Dolibarr module to synchronize calendars, project tasks and address book from CalDAV/CardDAV/ICS client tools such as Mozilla Thunderbird/Lightning or Android DAVDroid. Dolibarr becomes a CalDAV/CardDAV server.
2 |
--------------------------------------------------------------------------------
/doc/description_fr.html:
--------------------------------------------------------------------------------
1 | Module Dolibarr pour synchroniser les agendas, tâches de projet et carnet d'adresses depuis des outils client CalDAV/CardDAV/ICS tel que Mozilla Thunderbird/Lightning ou Android DAVDroid. Dolibarr devient un serveur CalDAV/CardDAV.
2 |
--------------------------------------------------------------------------------
/doc/description_lo_en.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Dolibarr module to synchronize calendars, project tasks and address
12 | book from CalDAV/CardDAV/ICS client tools such as Mozilla
13 | Thunderbird/Lightning or Android DAVx5. Dolibarr becomes a
14 | CalDAV/CardDAV server.
15 | Since version 2, this module allows to sync tasks, which can be
16 | created (according to setup) in projects from docs like proposals or
17 | orders.
18 | You obtain a great tool for driving your tech teams !
19 |
20 |
21 |
--------------------------------------------------------------------------------
/doc/description_lo_fr.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | Module Dolibarr pour synchroniser les agendas, tâches de projet et
12 | carnet d'adresses depuis des outils client CalDAV/CardDAV/ICS tel que
13 | Mozilla Thunderbird/Lightning ou Android DAVx5. Dolibarr devient un
14 | serveur CalDAV/CardDAV.
15 | A partir de la version 2, le module permet de synchroniser aussi
16 | les tâches des projets, qui peuvent être créées de façon
17 | paramétrable depuis les documents de type propositions ou commandes.
18 | Vous obtenez alors un outil de planification d’intervention pour
19 | vos équipes sur le terrain !
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/doc/documentation_lo_en.odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/doc/documentation_lo_en.odt
--------------------------------------------------------------------------------
/doc/documentation_lo_en.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/doc/documentation_lo_en.pdf
--------------------------------------------------------------------------------
/doc/logo_cdav_fil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/doc/logo_cdav_fil.png
--------------------------------------------------------------------------------
/doc/logo_cdav_v2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/doc/logo_cdav_v2.png
--------------------------------------------------------------------------------
/doc/long-description_en.html:
--------------------------------------------------------------------------------
1 | CardDAV / CalDAV and ICS synchronisation. It uses included Sabre/DAV library.
2 | You can :
3 |
4 | - Read and Edit Dolibarr calendars through CalDAV
5 | - Read and Edit Dolibarr project tasks through CalDAV
6 | - Read and Edit Dolibarr addressBooks through CardDAV
7 | - Read Dolibarr calendars through ICS Full version or only Free/Busy (hide details)
8 | - Access Dolibarr documents through WebDAV (if admin)
9 |
10 | Each user can access his/her contacts address book (public and own private contacts), his/her own calendar and other users calendars according to his/her rights.
11 | Dolibarr contact informations fill personnal informations in client software cards.
12 | Society informations (to which contact is attached) fill professional informations in client software cards.
13 | Cards updated in client software fill only Dolibarr contacts (not Society).
14 | It is possible to select which contacts to sync with CDAV_CONTACT_TAG configuration value in Home / Setup / Other setup. Enter a contact tag value and then only contacts with this tag will be synced (empty value for all).
15 | Calendar records with "Status / Percentage" set to "Not applicable" are converted to events in CalDAV (VEVENT), others are converted to tasks (VTODO).
16 | Recurring events are not handled.
17 | Module version: auto
Publisher/Licence: Befox SARL / GPLv3
User interface language: English/French
Help/Support: http://www.befox.fr/contact
Prerequisites:
18 |
19 | - Dolibarr min version: auto
20 | - Dolibarr max version: auto
21 |
22 | Install:
23 |
24 | - Download the archive file of module (.zip file) from web site DoliStore.com
25 | - Put the file into the root directory of Dolibarr.
26 | - Uncompress the zip file, for example with command
27 |
28 |
29 |
30 |
unzip modulefile.zip
31 |
32 |
33 |
34 | - Module is then available and can be activated.
35 |
36 |
--------------------------------------------------------------------------------
/doc/long-description_fr.html:
--------------------------------------------------------------------------------
1 | Synchronisation CardDAV / CalDAV et ICS. Ce module inclut la bibliothèque Sabre/DAV.
2 | Vous pouvez :
3 |
4 | - Lire et éditer les agendas Dolibarr au travers de CalDAV
5 | - Lire et éditer les tâches de projet au travers de CalDAV
6 | - Lire et éditer les carnets d'adresse au travers de CardDAV
7 | - Lire les agendas Dolibarr au travers d'ICS en vue complète ou en vue libre/occupé (detail masqué)
8 | - Accéder aux documents Dolibarr au travers de WebDAV (si utilisateur admin)
9 |
10 | Chaque utilisateur accède à ses contacts (publics ou ses contacts privés), à son agenda et ceux des autres utilisateurs en fonction de ses droits.
11 | Les informations de contact Dolibarr remplissent les champs personnels de la fiche contact.
12 | Les informations de tiers Dolibarr remplissent les champs professionnels de la fiche contact associée.
13 | Les fiches contact mise à jour sur le logiciel client n'alimentent que le contact Dolibarr (le Tiers n'est jamais modifié).
14 | Il est possible de sélectionner quels contacts sont synchronisés en spécifiant la catégorie/tag des contacts concernés. Par défaut tous les contacts sont synchronisés.
15 | Les enregistrement d'agenda avec un "Statut / Pourcentage" à "Non applicable" sont convertis en évènements CalDAV (VEVENT), les autres sont convertis en tâches (VTODO).
16 | Les évènements récurrents ne sont pas gérés.
17 | Module version: auto
Editeur/Licence: Befox SARL / GPLv3
Langage interface: Anglais
Assistance: http://www.befox.fr/contact
Prérequis:
18 |
19 | - Dolibarr min version: auto
20 | - Dolibarr max version: auto
21 |
22 | Installation:
23 |
24 | - Télécharger le fichier archive du module (.zip) depuis le site web DoliStore.com
25 | - Placer le fichier dans le répertoire racine de dolibarr.
26 | - Decompressez le fichier zip, par exemple par la commande
27 |
28 |
29 |
30 |
unzip fichiermodule.zip
31 |
32 |
33 |
34 | - Le module est alors disponible et activable.
35 |
36 |
--------------------------------------------------------------------------------
/doc/long-description_lo_en.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 | CardDAV / CalDAV and ICS synchronisation. It uses included
15 | Sabre/DAV library.
16 | You can :
17 |
18 |
19 | Read and Edit Dolibarr calendars
20 | through CalDAV
21 |
22 |
23 |
24 | Read and Edit Dolibarr project tasks
25 | through CalDAV
26 |
27 |
28 | Read and Edit Dolibarr
29 | addressBooks through CardDAV
30 |
31 |
32 | Read Dolibarr calendars through
33 | ICS Full version or only Free/Busy (hide details)
34 |
35 |
36 | Access Dolibarr documents through WebDAV (if admin)
37 |
38 |
39 | Each user can access his/her contacts address book (public and own
40 | private contacts), his/her own calendar and other users calendars
41 | according to his/her rights.
42 | Dolibarr contact informations fill personnal informations in
43 | client software cards.
44 | Society informations (to which contact is attached) fill
45 | professional informations in client software cards.
46 | Cards updated in client software fill only Dolibarr contacts (not
47 | Society).
48 | It is possible to select which contacts to sync with
49 | CDAV_CONTACT_TAG configuration value in Home / Setup / Other setup.
50 | Enter a contact tag value and then only contacts with this tag will
51 | be synced (empty value for all).
52 | Calendar records with "Status / Percentage" set to "Not
53 | applicable" are converted to events in CalDAV (VEVENT), others
54 | are converted to tasks (VTODO).
55 | Recurring events are not
56 | handled.
57 | Project tasks are synchronized to the calendar and/or
58 | remote tasks (no duplication in Dolibarr). Tasks descriptions
59 | containing lines beginning with “- “ generate new items that can
60 | then be checked, which advance the percentage of completion (Declared
61 | progress)
62 | Previously, task generation can be created
63 | automatically from documents attached to the project (proposals and /
64 | or orders) in a customizable way.
65 | Module version: auto
66 | Publisher/Licence:
67 | Befox SARL / GPLv3
68 | User
69 | interface language: English/French
70 | Help/Support:
71 | http://www.befox.fr/contact
72 | Prerequisites:
73 |
74 |
75 | Dolibarr min version: auto
76 |
77 |
78 | Dolibarr max version: auto
79 |
80 |
81 | Install:
82 |
83 |
84 | Download the archive file of
85 | module (.zip file) from web site DoliStore.com
86 |
87 |
88 | Put the file into the root
89 | directory of Dolibarr.
90 |
91 |
92 | Uncompress the zip file, for example with command
93 |
94 |
95 | unzip modulefile.zip
96 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/doc/long-description_lo_fr.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
12 |
13 |
14 | Synchronisation CardDAV / CalDAV et ICS. Ce module inclut la
15 | bibliothèque Sabre/DAV.
16 | Vous pouvez :
17 |
18 |
19 | Lire et éditer les agendas
20 | Dolibarr au travers de CalDAV
21 |
22 |
23 |
24 | Lire et éditer les tâches de projet
25 | Dolibarr au travers de CalDAV
26 |
27 |
28 | Lire et éditer les carnets
29 | d'adresse au travers de CardDAV
30 |
31 |
32 | Lire les agendas Dolibarr au
33 | travers d'ICS en vue complète ou en vue libre/occupé (détail
34 | masqué)
35 |
36 |
37 | Lire et éditer les tâches
38 | Dolibarr au travers de CalDAV
39 |
40 |
41 | Accéder aux documents Dolibarr au travers de WebDAV (si
42 | utilisateur admin)
43 |
44 |
45 | Chaque utilisateur accède à ses contacts (publics ou ses
46 | contacts privés), à son agenda et ceux des autres utilisateurs en
47 | fonction de ses droits, à ses tâches et celles des autres
48 | utilisateurs en fonction de ses droits.
49 | Les informations de contact Dolibarr remplissent les champs
50 | personnels de la fiche contact.
51 | Les informations de tiers Dolibarr remplissent les champs
52 | professionnels de la fiche contact associée.
53 | Les fiches contact mise à jour sur le logiciel client
54 | n'alimentent que le contact Dolibarr (le Tiers n'est jamais modifié).
55 | Il est possible de sélectionner quels contacts sont synchronisés
56 | en spécifiant la catégorie/tag des contacts concernés. Par défaut
57 | tous les contacts sont synchronisés.
58 | Les enregistrement d'agenda avec un "Statut / Pourcentage"
59 | à "Non applicable" sont convertis en évènements CalDAV
60 | (VEVENT), les autres sont convertis en tâches (VTODO).
61 | Les
62 | évènements récurrents ne sont pas gérés.
63 | Les tâches des projets sont synchronisées vers l’agenda et/ou
64 | les tâches distants (pas de duplication dans Dolibarr). La
65 | description des tâches contenant des lignes commençant par «- »
66 | génèrent des items sur le terrain qui peuvent alors être cochés
67 | et faire avancer le pourcentage de réalisation de la tâches
68 | ( Progression déclarée – Declared progress )
69 | Auparavant,
70 | la génération des tâches peuvent être créées automatiquement en
71 | provenance de documents attachés au projet (propositions et/ou
72 | commandes) et ce, de façon paramétrable.
73 |
74 |
75 |
76 |
77 | Module version: auto
78 | Editeur/Licence: Befox
79 | SARL / GPLv3
80 | Langage interface:
81 | Anglais
82 | Assistance:
83 | http://www.befox.fr/contact
84 | Prérequis:
85 |
86 |
87 | Dolibarr min version: auto
88 |
89 |
90 | Dolibarr max version: auto
91 |
92 |
93 | Installation:
94 |
95 |
96 | Télécharger le fichier archive
97 | du module (.zip) depuis le site web DoliStore.com
98 |
99 |
100 | Placer le fichier dans le
101 | répertoire racine de dolibarr.
102 |
103 |
104 | Decompressez le fichier zip, par exemple par la commande
105 |
106 |
107 | unzip fichiermodule.zip
108 |
113 |
114 |
115 |
--------------------------------------------------------------------------------
/ics.php:
--------------------------------------------------------------------------------
1 | 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; }
38 | if (!$res && $i > 0 && @file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
39 | if (!$res && $i > 0 && @file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
40 | // Try main.inc.php using relative path
41 | if (!$res && @file_exists("../main.inc.php")) $res = @include "../main.inc.php";
42 | if (!$res && @file_exists("../../main.inc.php")) $res = @include "../../main.inc.php";
43 | if (!$res && @file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
44 | if (!$res) die("Include of main fails");
45 |
46 | require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
47 |
48 | // Load traductions files requiredby by page
49 | $langs->load("cdav");
50 |
51 |
52 | //Get all event
53 | require_once './lib/cdav.lib.php';
54 |
55 |
56 | // define CDAV_CONTACT_TAG if not
57 | if(!defined('CDAV_CONTACT_TAG'))
58 | {
59 | if(isset($conf->global->CDAV_CONTACT_TAG))
60 | define('CDAV_CONTACT_TAG', $conf->global->CDAV_CONTACT_TAG);
61 | else
62 | define('CDAV_CONTACT_TAG', '');
63 | }
64 |
65 | // define CDAV_URI_KEY if not
66 | if(!defined('CDAV_URI_KEY'))
67 | {
68 | if(isset($conf->global->CDAV_URI_KEY))
69 | define('CDAV_URI_KEY', $conf->global->CDAV_URI_KEY);
70 | else
71 | define('CDAV_URI_KEY', substr(md5($_SERVER['HTTP_HOST']),0,8));
72 | }
73 |
74 | // define CDAV_TASK_USER_ROLE if not
75 | if(!defined('CDAV_TASK_USER_ROLE'))
76 | {
77 | if(isset($conf->global->CDAV_TASK_USER_ROLE))
78 | define('CDAV_TASK_USER_ROLE', $conf->global->CDAV_TASK_USER_ROLE);
79 | else
80 | die('Module CDav is not properly configured : Project user role not set !');
81 | }
82 |
83 | // define CDAV_SYNC_PAST if not
84 | if(!defined('CDAV_SYNC_PAST'))
85 | {
86 | if(isset($conf->global->CDAV_SYNC_PAST))
87 | define('CDAV_SYNC_PAST', $conf->global->CDAV_SYNC_PAST);
88 | else
89 | die('Module CDav is not properly configured : Period to sync not set !');
90 | }
91 |
92 | // define CDAV_SYNC_FUTURE if not
93 | if(!defined('CDAV_SYNC_FUTURE'))
94 | {
95 | if(isset($conf->global->CDAV_SYNC_FUTURE))
96 | define('CDAV_SYNC_FUTURE', $conf->global->CDAV_SYNC_FUTURE);
97 | else
98 | die('Module CDav is not properly configured : Period to sync not set !');
99 | }
100 |
101 | // define CDAV_TASK_SYNC if not
102 | if(!defined('CDAV_TASK_SYNC'))
103 | {
104 | if(isset($conf->global->CDAV_TASK_SYNC))
105 | define('CDAV_TASK_SYNC', $conf->global->CDAV_TASK_SYNC);
106 | else
107 | define('CDAV_TASK_SYNC', '0');
108 | }
109 |
110 | // define CDAV_THIRD_SYNC if not
111 | if(!defined('CDAV_THIRD_SYNC'))
112 | {
113 | if(isset($conf->global->CDAV_THIRD_SYNC))
114 | define('CDAV_THIRD_SYNC', $conf->global->CDAV_THIRD_SYNC);
115 | else
116 | define('CDAV_THIRD_SYNC', '0');
117 | }
118 |
119 | // define CDAV_MEMBER_SYNC if not
120 | if(!defined('CDAV_MEMBER_SYNC'))
121 | {
122 | if(isset($conf->global->CDAV_MEMBER_SYNC))
123 | define('CDAV_MEMBER_SYNC', $conf->global->CDAV_MEMBER_SYNC);
124 | else
125 | define('CDAV_MEMBER_SYNC', '0');
126 | }
127 |
128 | // 0 < CDAV_ADDRESSBOOK_ID_SHIFT = Contacts
129 | // CDAV_ADDRESSBOOK_ID_SHIFT < 2*CDAV_ADDRESSBOOK_ID_SHIFT = Thirdparties
130 | // 2*CDAV_ADDRESSBOOK_ID_SHIFT < 3*CDAV_ADDRESSBOOK_ID_SHIFT = Members
131 | define('CDAV_ADDRESSBOOK_ID_SHIFT', 100000);
132 |
133 | //parse Token
134 | $arrTmp = explode('+ø+', openssl_decrypt(base64url_decode(GETPOST('token')), 'aes-256-cbc', CDAV_URI_KEY, true));
135 |
136 | if(!is_array($arrTmp) || count($arrTmp)<2)
137 | {
138 | // use old encryption algo bf-ecb
139 | $arrTmp = explode('+ø+', openssl_decrypt(base64url_decode(GETPOST('token')), 'bf-ecb', CDAV_URI_KEY, true));
140 | }
141 |
142 | if (! isset($arrTmp[1]) || ! in_array(trim($arrTmp[1]), array('nolabel', 'full')))
143 | {
144 | echo 'Unauthorized Access !';
145 | exit;
146 | }
147 |
148 | $id = trim($arrTmp[0]);
149 | $type = trim($arrTmp[1]);
150 |
151 | header('Content-type: text/calendar; charset=utf-8');
152 | header('Content-Disposition: attachment; filename=Calendar-'.$id.'-'.$type.'.ics');
153 |
154 | //fake user having right on this calendar
155 | $user = new stdClass();
156 |
157 | $user->rights = new stdClass();
158 | $user->rights->agenda = new stdClass();
159 | $user->rights->agenda->myactions = new stdClass();
160 | $user->rights->agenda->allactions = new stdClass();
161 | $user->rights->societe = new stdClass();
162 | $user->rights->societe->client = new stdClass();
163 |
164 | $user->id = $id;
165 | $user->rights->agenda->myactions->read = true;
166 | $user->rights->agenda->allactions->read = true;
167 | $user->rights->societe->client->voir = false;
168 |
169 | $cdavLib = new CdavLib($user, $db, $langs);
170 |
171 | //Format them
172 | $arrEvents = $cdavLib->getFullCalendarObjects($id, true);
173 |
174 | echo "BEGIN:VCALENDAR\n";
175 | echo "VERSION:2.0\n";
176 | echo "PRODID:-//Dolibarr CDav//FR\n";
177 | foreach($arrEvents as $event)
178 | {
179 | if ($type == 'nolabel')
180 | {
181 | //Remove SUMMARY / DESCRIPTION / LOCATION
182 | $event['calendardata'] = preg_replace('#SUMMARY:.*[^\n]#', 'SUMMARY:'.$langs->trans('Busy'), $event['calendardata']);//FIXME translate busy !!
183 | $event['calendardata'] = preg_replace('#DESCRIPTION:.*[^\n]#', 'DESCRIPTION:.', $event['calendardata']);
184 | $event['calendardata'] = preg_replace('#LOCATION:.*[^\n]#', 'LOCATION:', $event['calendardata']);
185 | echo $event['calendardata'];
186 | }
187 | else
188 | echo $event['calendardata'];
189 | }
190 | echo "END:VCALENDAR\n";
191 |
--------------------------------------------------------------------------------
/img/object_cdav.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Befox/cdav/4a5ff876207011a7fe67f2580a28805b7825ca62/img/object_cdav.png
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | BinaryEye (available on F-Droid) to flash the qrcode and autoconfig DavX5!
17 |
--------------------------------------------------------------------------------
/langs/fr_FR/cdav.lang:
--------------------------------------------------------------------------------
1 | # Dolibarr language file - Source file is en_US - cdav
2 | CardDAVurl=URL CardDAV
3 | CalDAVurl=URL CalDAV
4 | ICSurl=URL ICS
5 | URLforICS=Cette URL peut être utilisée avec un client de synchronisation (lecture seule) :
6 | Full=Complet
7 | NoLabel=Sans label
8 | Busy=Occupé
9 | URLGeneric=Ces URL peuvent être utilisées avec un client de synchronisation CalDAV/CardDAV :
10 | URLforCardDAV=Si votre client ne détecte pas votre carnet d'adresse cette URL complète peut être précisée :
11 | URLforCalDAV=Si votre client ne détecte pas vos agendas ces URLs complètes peuvent être précisées :
12 | DurationEx=Durée (ex: 4H, 3J)
13 | ActivateDavX5autoURL=Activer la génération de qrcode d'auto configuration pour davx5 ?
14 | ActivateDavX5autoURLTooltip=Si vous activez cette option un qrcode d'auto-configuration vous sera proposé pour ne pas avoir à saisir toutes les données à la main sur votre smartphone
15 | URLForDavX5=Configuration automatique pour DavX5
16 | URLForDavX5Tooltip=Utilisez le logiciel libre BinaryEye (dispo sur F-Droid) pour flasher le qrcode et autoconfigurer DavX5 !
17 |
18 | EnableMembersSync=Enable members sync
19 | GenerateAddressbookForMembership=Generate an address book for membership
20 |
--------------------------------------------------------------------------------
/lib/cdav.lib.php:
--------------------------------------------------------------------------------
1 | user = $user;
21 | $this->db = $db;
22 | $this->langs = $langs;
23 | }
24 |
25 | /**
26 | * Base sql request for calendar events
27 | *
28 | * @param int calendar user id
29 | * @param int actioncomm object id
30 | * @return string
31 | */
32 | public function getSqlCalEvents($calid, $oid=false, $ouri=false)
33 | {
34 | // TODO : replace GROUP_CONCAT by
35 | $sql = 'SELECT
36 | "ev" elem_source,
37 | a.tms AS lastupd,
38 | a.*,
39 | sp.firstname,
40 | sp.lastname,
41 | sp.address,
42 | sp.zip,
43 | sp.town,
44 | co.label country_label,
45 | sp.phone,
46 | sp.phone_perso,
47 | sp.phone_mobile,
48 | s.nom AS soc_nom,
49 | s.address soc_address,
50 | s.zip soc_zip,
51 | s.town soc_town,
52 | cos.label soc_country_label,
53 | s.phone soc_phone,
54 | p.ref proj_ref,
55 | p.title proj_title,
56 | p.description proj_desc,
57 | ac.sourceuid,
58 | (SELECT GROUP_CONCAT(u.login) FROM '.MAIN_DB_PREFIX.'actioncomm_resources ar
59 | LEFT OUTER JOIN '.MAIN_DB_PREFIX.'user AS u ON (u.rowid=fk_element)
60 | WHERE ar.element_type=\'user\' AND fk_actioncomm=a.id) AS other_users
61 | FROM '.MAIN_DB_PREFIX.'actioncomm AS a';
62 | if (! $this->user->rights->societe->client->voir )//FIXME si 'voir' on voit plus de chose ?
63 | {
64 | $sql.=' LEFT OUTER JOIN '.MAIN_DB_PREFIX.'societe_commerciaux AS sc ON (a.fk_soc = sc.fk_soc AND sc.fk_user='.$this->user->id.')
65 | LEFT JOIN '.MAIN_DB_PREFIX.'societe AS s ON (s.rowid = sc.fk_soc)
66 | LEFT JOIN '.MAIN_DB_PREFIX.'socpeople AS sp ON (sp.fk_soc = sc.fk_soc AND sp.rowid = a.fk_contact)
67 | LEFT JOIN '.MAIN_DB_PREFIX.'actioncomm_cdav AS ac ON (a.id = ac.fk_object)';
68 | }
69 | else
70 | {
71 | $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'societe AS s ON (s.rowid = a.fk_soc)
72 | LEFT JOIN '.MAIN_DB_PREFIX.'socpeople AS sp ON (sp.rowid = a.fk_contact)
73 | LEFT JOIN '.MAIN_DB_PREFIX.'actioncomm_cdav AS ac ON (a.id = ac.fk_object)';
74 | }
75 |
76 | $sql.=' LEFT JOIN '.MAIN_DB_PREFIX.'projet AS p ON (p.rowid = a.fk_project)
77 | LEFT JOIN '.MAIN_DB_PREFIX.'c_country as co ON co.rowid = sp.fk_pays
78 | LEFT JOIN '.MAIN_DB_PREFIX.'c_country as cos ON cos.rowid = s.fk_pays
79 | WHERE a.id IN (SELECT ar.fk_actioncomm FROM '.MAIN_DB_PREFIX.'actioncomm_resources ar WHERE ar.element_type=\'user\' AND ar.fk_element='.intval($calid).')
80 | AND a.code IN (SELECT cac.code FROM '.MAIN_DB_PREFIX.'c_actioncomm cac WHERE cac.type<>\'systemauto\')
81 | AND a.entity IN ('.getEntity('societe', 1).')';
82 | if($oid!==false) {
83 | if($ouri===false)
84 | {
85 | $sql.=' AND a.id = '.intval($oid);
86 | }
87 | else
88 | {
89 | $sql.=' AND (a.id = '.intval($oid).' OR ac.uuidext = \''.$this->db->escape($ouri).'\' OR ac.sourceuid = \''.$this->db->escape($ouri).'\')';
90 | }
91 | }
92 | else
93 | {
94 | $sql.=' AND COALESCE(a.datep2,a.datep)>="'.date('Y-m-d 00:00:00',time()-86400*CDAV_SYNC_PAST).'"
95 | AND a.datep<="'.date('Y-m-d 23:59:59',time()+86400*CDAV_SYNC_FUTURE).'"';
96 | }
97 |
98 | return $sql;
99 |
100 | }
101 | /**
102 | * Base sql request for project tasks
103 | *
104 | * @param int calendar user id
105 | * @param int task object id
106 | * @param string elem_source 'pt'=Project TODO 'pe'=Project EVENT
107 | * @return string
108 | */
109 | public function getSqlProjectTasks($calid, $oid=false, $elem_source)
110 | {
111 | global $conf;
112 |
113 | if(!$conf->project->enabled || (isset($conf->global->PROJECT_HIDE_TASKS) && $conf->global->PROJECT_HIDE_TASKS))
114 | return false;
115 |
116 | if(intval(CDAV_TASK_SYNC)==0 || (intval(CDAV_TASK_SYNC)==1 && $elem_source=='pt'))
117 | return false;
118 |
119 | if(intval(CDAV_TASK_SYNC)==0 || (intval(CDAV_TASK_SYNC)==2 && $elem_source=='pe'))
120 | return false;
121 |
122 | // TODO : replace GROUP_CONCAT by
123 | $sql = 'SELECT
124 | "'.$elem_source.'" elem_source,
125 | pt.rowid AS id,
126 | pt.tms AS lastupd,
127 | pt.*,
128 | p.ref proj_ref,
129 | p.title proj_title,
130 | p.description proj_desc,
131 | s.nom AS soc_nom,
132 | s.address soc_address,
133 | s.zip soc_zip,
134 | s.town soc_town,
135 | cos.label soc_country_label,
136 | s.phone soc_phone,
137 | (SELECT GROUP_CONCAT(u.login) FROM '.MAIN_DB_PREFIX.'element_contact gec
138 | LEFT JOIN '.MAIN_DB_PREFIX.'c_type_contact as gtc ON (gtc.rowid=gec.fk_c_type_contact AND gtc.element="project_task" AND gtc.source="internal")
139 | LEFT OUTER JOIN '.MAIN_DB_PREFIX.'user AS u ON (u.rowid=gec.fk_socpeople)
140 | WHERE gec.element_id=pt.rowid AND gtc.element="project_task" AND u.login IS NOT NULL) AS other_users,
141 | (SELECT GROUP_CONCAT(sp.firstname, " ", sp.lastname) FROM '.MAIN_DB_PREFIX.'element_contact gec
142 | LEFT JOIN '.MAIN_DB_PREFIX.'c_type_contact as gtc ON (gtc.rowid=gec.fk_c_type_contact AND gtc.element="project_task" AND gtc.source="external")
143 | LEFT JOIN '.MAIN_DB_PREFIX.'socpeople AS sp ON (sp.rowid=gec.fk_socpeople)
144 | WHERE gec.element_id=pt.rowid AND gtc.element="project_task" AND sp.lastname IS NOT NULL) AS other_contacts
145 | FROM '.MAIN_DB_PREFIX.'projet_task AS pt
146 | LEFT JOIN '.MAIN_DB_PREFIX.'projet AS p ON (p.rowid = pt.fk_projet)
147 | LEFT JOIN '.MAIN_DB_PREFIX.'societe AS s ON (s.rowid = p.fk_soc)
148 | LEFT JOIN '.MAIN_DB_PREFIX.'c_country as cos ON cos.rowid = s.fk_pays
149 | LEFT JOIN '.MAIN_DB_PREFIX.'element_contact as ec ON (ec.element_id=pt.rowid)
150 | LEFT JOIN '.MAIN_DB_PREFIX.'c_type_contact as tc ON (tc.rowid=ec.fk_c_type_contact AND tc.element="project_task" AND tc.source="internal")
151 | WHERE tc.element="project_task" AND tc.source="internal" AND ec.fk_socpeople='.intval($calid).'
152 | AND pt.entity IN ('.getEntity('societe', 1).')';
153 | if($oid!==false)
154 | {
155 | $sql.=' AND pt.rowid = '.intval($oid);
156 | }
157 | else
158 | {
159 | $sql.=' AND COALESCE(pt.datee,pt.dateo)>="'.date('Y-m-d 00:00:00',time()-86400*CDAV_SYNC_PAST).'"
160 | AND pt.dateo<="'.date('Y-m-d 23:59:59',time()+86400*CDAV_SYNC_FUTURE).'"';
161 | }
162 | return $sql;
163 |
164 | }
165 |
166 | /**
167 | * Convert calendar row to VCalendar string
168 | *
169 | * @param row object
170 | * @return string
171 | */
172 | public function toVCalendar($calid, $obj, $bHeader)
173 | {
174 | if($obj->elem_source=='ev') // Calendar Event
175 | {
176 | $categ = [];
177 | /*if($obj->soc_client)
178 | {
179 | $nick[] = $obj->soc_code_client;
180 | $categ[] = $this->langs->transnoentitiesnoconv('Customer');
181 | }*/
182 |
183 | $location=trim(str_replace(array("\r","\t","\n"),' ',$obj->location));
184 |
185 | // contact address
186 | if(empty($location) && !empty($obj->address))
187 | {
188 | $location = trim(str_replace(array("\r","\t","\n"),' ', $obj->address));
189 | $location = trim($location.', '.$obj->zip);
190 | $location = trim($location.' '.$obj->town);
191 | $location = trim($location.', '.$obj->country_label);
192 | }
193 |
194 | // contact address
195 | if(empty($location) && !empty($obj->soc_address))
196 | {
197 | $location = trim(str_replace(array("\r","\t","\n"),' ', $obj->soc_address));
198 | $location = trim($location.', '.$obj->soc_zip);
199 | $location = trim($location.' '.$obj->soc_town);
200 | $location = trim($location.', '.$obj->soc_country_label);
201 | }
202 |
203 | $address=explode("\n",$obj->address,2);
204 | foreach($address as $kAddr => $vAddr)
205 | {
206 | $address[$kAddr] = trim(str_replace(array("\r","\t"),' ', str_replace("\n",' | ', trim($vAddr))));
207 | }
208 | $address[]='';
209 | $address[]='';
210 |
211 | if($obj->percent==-1 && trim($obj->datep)!='')
212 | $type='VEVENT';
213 | else
214 | $type='VTODO';
215 |
216 | $timezone = date_default_timezone_get();
217 |
218 | $caldata ="";
219 | if($bHeader)
220 | {
221 | $caldata ="BEGIN:VCALENDAR\n";
222 | $caldata.="VERSION:2.0\n";
223 | $caldata.="PRODID:-//Dolibarr CDav//FR\n";
224 | }
225 | $caldata.="BEGIN:".$type."\n";
226 | $caldata.="CREATED:".gmdate('Ymd\THis', strtotime($obj->datec))."Z\n";
227 | $caldata.="LAST-MODIFIED:".gmdate('Ymd\THis', strtotime($obj->lastupd))."Z\n";
228 | $caldata.="DTSTAMP:".gmdate('Ymd\THis', strtotime($obj->lastupd))."Z\n";
229 | if($obj->sourceuid=='')
230 | $caldata.="UID:".$obj->id.'-ev-'./*$calid.'-cal-'.*/ CDAV_URI_KEY."\n";
231 | else
232 | $caldata.="UID:".$obj->sourceuid."\n";
233 | $caldata.="SUMMARY:".strtr(trim($obj->label), array("\n"=>"\\n", "\r"=>""))."\n";
234 | $caldata.="URL:".dol_buildpath("/comm/action/card.php?id=".$obj->id, 2)."\n";
235 | $caldata.="LOCATION:".strtr(trim($location), array("\n"=>"\\n", "\r"=>""))."\n";
236 | $caldata.="PRIORITY:".$obj->priority."\n";
237 | if($obj->fulldayevent)
238 | {
239 | $caldata.="DTSTART;VALUE=DATE:".date('Ymd', strtotime($obj->datep))."\n";
240 | if($type=='VEVENT')
241 | {
242 | if(trim($obj->datep2)>trim($obj->datep))
243 | $caldata.="DTEND;VALUE=DATE:".date('Ymd', strtotime($obj->datep2)+1)."\n";
244 | else
245 | $caldata.="DTEND;VALUE=DATE:".date('Ymd', strtotime($obj->datep)+(25*3600))."\n";
246 | }
247 | elseif(trim($obj->datep2)!='')
248 | $caldata.="DUE;VALUE=DATE:".date('Ymd', strtotime($obj->datep2)+1)."\n";
249 | }
250 | else
251 | {
252 | $caldata.="DTSTART;TZID=".$timezone.":".strtr($obj->datep,array(" "=>"T", ":"=>"", "-"=>""))."\n";
253 | if($type=='VEVENT')
254 | {
255 | if(trim($obj->datep2)>trim($obj->datep))
256 | $caldata.="DTEND;TZID=".$timezone.":".strtr($obj->datep2,array(" "=>"T", ":"=>"", "-"=>""))."\n";
257 | else
258 | $caldata.="DTEND;TZID=".$timezone.":".strtr($obj->datep,array(" "=>"T", ":"=>"", "-"=>""))."\n";
259 | }
260 | elseif(trim($obj->datep2)!='')
261 | $caldata.="DUE;TZID=".$timezone.":".strtr($obj->datep2,array(" "=>"T", ":"=>"", "-"=>""))."\n";
262 | }
263 | $caldata.="CLASS:PUBLIC\n";
264 | if($obj->transparency==1)
265 | $caldata.="TRANSP:TRANSPARENT\n";
266 | else
267 | $caldata.="TRANSP:OPAQUE\n";
268 |
269 | if($type=='VEVENT')
270 | $caldata.="STATUS:CONFIRMED\n";
271 | elseif($obj->percent==0)
272 | $caldata.="STATUS:NEEDS-ACTION\n";
273 | elseif($obj->percent==100)
274 | $caldata.="STATUS:COMPLETED\n";
275 | else
276 | {
277 | $caldata.="STATUS:IN-PROCESS\n";
278 | $caldata.="PERCENT-COMPLETE:".$obj->percent."\n";
279 | }
280 |
281 | $caldata.="DESCRIPTION:";
282 | if(!empty($obj->proj_ref))
283 | $caldata.="💼📋 [".$obj->proj_ref."] ".$obj->proj_title."\\n";
284 | if(!empty($obj->proj_desc))
285 | $caldata.="💼⚠️ ".strtr(trim(strip_tags($obj->proj_desc)), array("\n"=>"\\n💼⚠️ ", "\r"=>""))."\\n";
286 | if(!empty($obj->soc_town))
287 | $caldata.="💼🏁 ".strtr(trim($obj->soc_town), array("\n"=>"\\n", "\r"=>""))."\\n";
288 | if(!empty($obj->soc_nom))
289 | $caldata.="💼🏢 ".strtr(trim($obj->soc_nom), array("\n"=>"\\n", "\r"=>""))."\\n";
290 | if(!empty($obj->soc_phone))
291 | $caldata.="💼☎️ ".$obj->soc_phone."\\n";
292 | if(!empty($obj->firstname) || !empty($obj->lastname))
293 | $caldata.="💼👨 ".trim($obj->firstname.' '.$obj->lastname)."\\n";
294 | if(!empty($obj->phone) || !empty($obj->phone_perso) || !empty($obj->phone_mobile))
295 | $caldata.="💼📞 ".trim($obj->phone.' '.$obj->phone_perso.' '.$obj->phone_mobile)."\\n";
296 | // removed because unable to swap from one calendar to an other with extrenal client
297 | // if(strpos($obj->other_users,',')) // several
298 | // $caldata.="💼USR: ".$obj->other_users."\\n";
299 | if($type=='VEVENT')
300 | $caldata.=strtr(trim($obj->note), array("\n"=>"\\n", "\r"=>""));
301 | else
302 | $caldata.=strtr("\n".trim($obj->note), array("\n- ["=>"\\n[", "\n- "=>"\\n[ ] ", "[x] [ ]"=>"[x]", "[ ] [x]"=>"[x]", "[x] [x]"=>"[x]", "[ ] [ ]"=>"[ ]", "\n"=>"\\n", "\r"=>""));
303 | $caldata.="\n";
304 |
305 | $caldata.="END:".$type."\n";
306 | if($bHeader)
307 | $caldata.="END:VCALENDAR\n";
308 | }
309 | elseif(substr($obj->elem_source,0,1)=='p') // Project Task pe/pt
310 | {
311 | if($obj->elem_source=='pe')
312 | $type='VEVENT';
313 | else // 'pt'
314 | $type='VTODO';
315 |
316 | $location='';
317 |
318 | // soc address
319 | if(!empty($obj->soc_address))
320 | {
321 | $location = trim(str_replace(array("\r","\t","\n"),' ', $obj->soc_address));
322 | $location = trim($location.', '.$obj->soc_zip);
323 | $location = trim($location.' '.$obj->soc_town);
324 | $location = trim($location.', '.$obj->soc_country_label);
325 | }
326 |
327 | $timezone = date_default_timezone_get();
328 |
329 | $caldata ="BEGIN:VCALENDAR\n";
330 | $caldata.="VERSION:2.0\n";
331 | $caldata.="PRODID:-//Dolibarr CDav//FR\n";
332 | $caldata.="BEGIN:".$type."\n";
333 | $caldata.="CREATED:".gmdate('Ymd\THis', strtotime($obj->datec))."Z\n";
334 | $caldata.="LAST-MODIFIED:".gmdate('Ymd\THis', strtotime($obj->lastupd))."Z\n";
335 | $caldata.="DTSTAMP:".gmdate('Ymd\THis', strtotime($obj->lastupd))."Z\n";
336 | $caldata.="UID:".$obj->id.'-'.$obj->elem_source.'-'./*$calid.'-cal-'.*/ CDAV_URI_KEY."\n";
337 | $caldata.="SUMMARY:[".strtr(trim($obj->proj_title), array("\n"=>"\\n", "\r"=>""))."]".strtr(trim($obj->label), array("\n"=>"\\n", "\r"=>""))."\n";
338 | $caldata.="URL:".dol_buildpath("/projet/tasks/task.php?id=".$obj->id."&withproject=".$obj->fk_projet,2)."\n";
339 | $caldata.="LOCATION:".strtr(trim($location), array("\n"=>"\\n", "\r"=>""))."\n";
340 | $caldata.="PRIORITY:".$obj->priority."\n";
341 |
342 | $caldata.="DTSTART;TZID=".$timezone.":".strtr($obj->dateo,array(" "=>"T", ":"=>"", "-"=>""))."\n";
343 | if($type=='VEVENT')
344 | {
345 | if(trim($obj->datee)>trim($obj->dateo))
346 | $caldata.="DTEND;TZID=".$timezone.":".strtr($obj->datee,array(" "=>"T", ":"=>"", "-"=>""))."\n";
347 | else
348 | $caldata.="DTEND;TZID=".$timezone.":".strtr($obj->dateo,array(" "=>"T", ":"=>"", "-"=>""))."\n";
349 | }
350 | elseif(trim($obj->datee)!='')
351 | $caldata.="DUE;TZID=".$timezone.":".strtr($obj->datee,array(" "=>"T", ":"=>"", "-"=>""))."\n";
352 |
353 | $caldata.="CLASS:PUBLIC\n";
354 | $caldata.="TRANSP:OPAQUE\n";
355 |
356 | if($type=='VEVENT')
357 | $caldata.="STATUS:CONFIRMED\n";
358 | elseif($obj->progress==0)
359 | $caldata.="STATUS:NEEDS-ACTION\n";
360 | elseif($obj->progress==100)
361 | $caldata.="STATUS:COMPLETED\n";
362 | else
363 | {
364 | $caldata.="STATUS:IN-PROCESS\n";
365 | $caldata.="PERCENT-COMPLETE:".$obj->progress."\n";
366 | }
367 |
368 | $caldata.="DESCRIPTION:";
369 | if(!empty($obj->proj_desc))
370 | $caldata.="💼⚠️ ".strtr(trim(strip_tags($obj->proj_desc)), array("\n"=>"\\n💼⚠️ ", "\r"=>""))."\\n";
371 | if(!empty($obj->soc_town))
372 | $caldata.="💼🏁 ".$obj->soc_town."\\n";
373 | if(!empty($obj->soc_nom))
374 | $caldata.="💼🏢 ".$obj->soc_nom."\\n";
375 | if(!empty($obj->soc_phone))
376 | $caldata.="💼☎️ ".$obj->soc_phone."\\n";
377 | if(!empty($obj->other_contacts))
378 | $caldata.="💼👨 ".$obj->other_contacts."\\n";
379 | if(!empty($obj->proj_ref))
380 | $caldata.="💼📋 [".$obj->proj_ref."/".$obj->ref."] ".$obj->proj_title."\\n";
381 | if(!empty($obj->note_public))
382 | $caldata.="💼📝 ".strtr(trim(strip_tags($obj->note_public)), array("\n"=>"\\n💼📝 ", "\r"=>""))."\\n";
383 | //removed because unable to swap from one calendar to an other with external client
384 | // if(!empty($obj->note_private))
385 | // $caldata.="💼🔒 ".strtr(trim(strip_tags($obj->note_private)), array("\n"=>"\\n💼🔒 ", "\r"=>""))."\\n";
386 | $caldata.=strtr("\n".trim($obj->description), array("\n- ["=>"\\n[", "\n- "=>"\\n[ ] ", "[x] [ ]"=>"[x]", "[ ] [x]"=>"[x]", "[x] [x]"=>"[x]", "[ ] [ ]"=>"[ ]", "\n"=>"\\n", "\r"=>""));
387 | // removed because unable to swap from one calendar to an other with external client
388 | // if(strpos($obj->other_users,',')) // several
389 | // $caldata.="💼USR: ".$obj->other_users."\\n";
390 | $caldata.="\n";
391 |
392 | $caldata.="END:".$type."\n";
393 | if($bHeader)
394 | $caldata.="END:VCALENDAR\n";
395 | }
396 |
397 | return $caldata;
398 | }
399 |
400 | public function getFullCalendarObjects($calendarId, $bCalendarData)
401 | {
402 | if(function_exists("debug_log"))
403 | debug_log("getCalendarObjects( $calendarId , $bCalendarData )");
404 |
405 | $calid = intval($calendarId);
406 | $calevents = [] ;
407 | $rSql = [] ;
408 |
409 | if(! $this->user->rights->agenda->myactions->read)
410 | return $calevents;
411 |
412 | if($calid!=$this->user->id && (!isset($this->user->rights->agenda->allactions->read) || !$this->user->rights->agenda->allactions->read))
413 | return $calevents;
414 |
415 | $rSql['ev'] = $this->getSqlCalEvents($calid);
416 | $rSql['pe'] = $this->getSqlProjectTasks($calid, false, 'pe');
417 | $rSql['pt'] = $this->getSqlProjectTasks($calid, false, 'pt');
418 |
419 | foreach($rSql as $elem_source => $sql)
420 | {
421 | if($sql=='')
422 | continue;
423 | $result = $this->db->query($sql);
424 |
425 | if ($result)
426 | {
427 | while ($obj = $this->db->fetch_object($result))
428 | {
429 | $calendardata = $this->toVCalendar($calid, $obj, false);
430 |
431 | if($bCalendarData)
432 | {
433 | $calevents[] = [
434 | 'calendardata' => $calendardata,
435 | 'uri' => $obj->id.'-'.$elem_source.'-'.CDAV_URI_KEY,
436 | 'lastmodified' => strtotime($obj->lastupd),
437 | 'etag' => '"'.md5($calendardata).'"',
438 | 'calendarid' => $calendarId,
439 | 'size' => strlen($calendardata),
440 | 'component' => strpos($calendardata, 'BEGIN:VEVENT')>0 ? 'vevent' : 'vtodo',
441 | ];
442 | }
443 | else
444 | {
445 | $calevents[] = [
446 | // 'calendardata' => $calendardata, not necessary because etag+size are present
447 | 'uri' => $obj->id.'-'.$elem_source.'-'.CDAV_URI_KEY,
448 | 'lastmodified' => strtotime($obj->lastupd),
449 | 'etag' => '"'.md5($calendardata).'"',
450 | 'calendarid' => $calendarId,
451 | 'size' => strlen($calendardata),
452 | 'component' => strpos($calendardata, 'BEGIN:VEVENT')>0 ? 'vevent' : 'vtodo',
453 | ];
454 | }
455 | }
456 | }
457 | }
458 | return $calevents;
459 | }
460 |
461 | }
462 |
--------------------------------------------------------------------------------
/server.php:
--------------------------------------------------------------------------------
1 | 1)
52 | {
53 | $_SERVER['PHP_AUTH_USER'] = $rAuth[0];
54 | $_SERVER['PHP_AUTH_PW'] = $rAuth[1];
55 | }
56 | }
57 |
58 | // HTTP auth workaround for php in fastcgi mode REDIRECT_HTTP_AUTHORIZATION set by rewrite engine in .htaccess
59 | if( isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) &&
60 | (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW'])) )
61 | {
62 | $rAuth = explode(':', base64_decode(substr($_SERVER['REDIRECT_HTTP_AUTHORIZATION'], 6)));
63 |
64 | if(count($rAuth)>1)
65 | {
66 | $_SERVER['PHP_AUTH_USER'] = $rAuth[0];
67 | $_SERVER['PHP_AUTH_PW'] = $rAuth[1];
68 | }
69 | }
70 |
71 | define('NOTOKENRENEWAL',1); // Disables token renewal
72 | if (! defined('NOLOGIN')) define('NOLOGIN','1');
73 | if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK','1'); // We accept to go on this page from external web site.
74 | if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1');
75 | if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1');
76 | if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1');
77 | function llxHeader() { }
78 | function llxFooter() { }
79 |
80 | // Load Dolibarr environment
81 | $res = 0;
82 | // Try main.inc.php into web root known defined into CONTEXT_DOCUMENT_ROOT (not always defined)
83 | if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) $res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
84 | // Try main.inc.php into web root detected using web root calculated from SCRIPT_FILENAME
85 | $tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME']; $tmp2 = realpath(__FILE__); $i = strlen($tmp) - 1; $j = strlen($tmp2) - 1;
86 | while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) { $i--; $j--; }
87 | if (!$res && $i > 0 && @file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) $res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
88 | if (!$res && $i > 0 && @file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) $res = @include dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php";
89 | // Try main.inc.php using relative path
90 | if (!$res && @file_exists("../main.inc.php")) $res = @include "../main.inc.php";
91 | if (!$res && @file_exists("../../main.inc.php")) $res = @include "../../main.inc.php";
92 | if (!$res && @file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
93 | if (!$res) die("Include of main fails");
94 |
95 | if(!defined('DOL_DOCUMENT_ROOT'))
96 | define('DOL_DOCUMENT_ROOT', $dolibarr_main_document_root);
97 |
98 | require DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; // auth method
99 | require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
100 |
101 | if(!$conf->cdav->enabled)
102 | die('module CDav not enabled !');
103 |
104 | set_error_handler("exception_error_handler", E_ERROR | E_USER_ERROR |
105 | E_CORE_ERROR | E_COMPILE_ERROR | E_RECOVERABLE_ERROR );
106 |
107 |
108 | require_once './lib/cdav.lib.php';
109 |
110 | // define CDAV_CONTACT_TAG if not
111 | if(!defined('CDAV_CONTACT_TAG'))
112 | {
113 | if(isset($conf->global->CDAV_CONTACT_TAG))
114 | define('CDAV_CONTACT_TAG', $conf->global->CDAV_CONTACT_TAG);
115 | else
116 | define('CDAV_CONTACT_TAG', '');
117 | }
118 |
119 | // define CDAV_URI_KEY if not
120 | if(!defined('CDAV_URI_KEY'))
121 | {
122 | if(isset($conf->global->CDAV_URI_KEY))
123 | define('CDAV_URI_KEY', $conf->global->CDAV_URI_KEY);
124 | else
125 | define('CDAV_URI_KEY', substr(md5($_SERVER['HTTP_HOST']),0,8));
126 | }
127 |
128 | // define CDAV_TASK_USER_ROLE if not
129 | if(!defined('CDAV_TASK_USER_ROLE'))
130 | {
131 | if(isset($conf->global->CDAV_TASK_USER_ROLE))
132 | define('CDAV_TASK_USER_ROLE', $conf->global->CDAV_TASK_USER_ROLE);
133 | else
134 | die('Module CDav is not properly configured : Project user role not set !');
135 | }
136 |
137 | // define CDAV_SYNC_PAST if not
138 | if(!defined('CDAV_SYNC_PAST'))
139 | {
140 | if(isset($conf->global->CDAV_SYNC_PAST))
141 | define('CDAV_SYNC_PAST', $conf->global->CDAV_SYNC_PAST);
142 | else
143 | die('Module CDav is not properly configured : Period to sync not set !');
144 | }
145 |
146 | // define CDAV_SYNC_FUTURE if not
147 | if(!defined('CDAV_SYNC_FUTURE'))
148 | {
149 | if(isset($conf->global->CDAV_SYNC_FUTURE))
150 | define('CDAV_SYNC_FUTURE', $conf->global->CDAV_SYNC_FUTURE);
151 | else
152 | die('Module CDav is not properly configured : Period to sync not set !');
153 | }
154 |
155 | // define CDAV_TASK_SYNC if not
156 | if(!defined('CDAV_TASK_SYNC'))
157 | {
158 | if(isset($conf->global->CDAV_TASK_SYNC))
159 | define('CDAV_TASK_SYNC', $conf->global->CDAV_TASK_SYNC);
160 | else
161 | define('CDAV_TASK_SYNC', '0');
162 | }
163 |
164 | // define CDAV_THIRD_SYNC if not
165 | if(!defined('CDAV_THIRD_SYNC'))
166 | {
167 | if(isset($conf->global->CDAV_THIRD_SYNC))
168 | define('CDAV_THIRD_SYNC', $conf->global->CDAV_THIRD_SYNC);
169 | else
170 | define('CDAV_THIRD_SYNC', '0');
171 | }
172 |
173 | // define CDAV_MEMBER_SYNC if not
174 | if(!defined('CDAV_MEMBER_SYNC'))
175 | {
176 | if(isset($conf->global->CDAV_MEMBER_SYNC))
177 | define('CDAV_MEMBER_SYNC', $conf->global->CDAV_MEMBER_SYNC);
178 | else
179 | define('CDAV_MEMBER_SYNC', '0');
180 | }
181 |
182 | // 0 < CDAV_ADDRESSBOOK_ID_SHIFT = Contacts
183 | // CDAV_ADDRESSBOOK_ID_SHIFT < 2*CDAV_ADDRESSBOOK_ID_SHIFT = Thirdparties
184 | // 2*CDAV_ADDRESSBOOK_ID_SHIFT < 3*CDAV_ADDRESSBOOK_ID_SHIFT = Members
185 | define('CDAV_ADDRESSBOOK_ID_SHIFT', 100000);
186 |
187 | // Sabre/dav configuration
188 |
189 | use Sabre\DAV;
190 | use Sabre\DAVACL;
191 |
192 | // The autoloader
193 | require DOL_DOCUMENT_ROOT.'/includes/sabre/autoload.php';
194 | require './class/PrincipalsDolibarr.php';
195 | require './class/CardDAVDolibarr.php';
196 | require './class/CalDAVDolibarr.php';
197 |
198 | $user = new User($db);
199 |
200 | if(isset($_SERVER['PHP_AUTH_USER']) && $_SERVER['PHP_AUTH_USER']!='')
201 | {
202 | $user->fetch('',$_SERVER['PHP_AUTH_USER']);
203 | $user->getrights();
204 | }
205 |
206 | $cdavLib = new CdavLib($user, $db, $langs);
207 |
208 | // Authentication
209 | $authBackend = new DAV\Auth\Backend\BasicCallBack(function ($username, $password)
210 | {
211 | global $user;
212 | global $conf;
213 | global $dolibarr_main_authentication;
214 |
215 |
216 | if ( ! isset($user->login) || $user->login=='')
217 | {
218 | debug_log("Authentication failed 1 for user $username with pass ".str_pad('', strlen($password), '*'));
219 | return false;
220 | }
221 | if (!empty($user->societe_id) || !empty($user->socid)) // external user
222 | {
223 | debug_log("Authentication failed 2 for user $username with pass ".str_pad('', strlen($password), '*'));
224 | return false;
225 | }
226 | if ($user->login!=$username)
227 | {
228 | debug_log("Authentication failed 3 for user $username with pass ".str_pad('', strlen($password), '*'));
229 | return false;
230 | }
231 | /*if ($user->pass_indatabase_crypted == '' || dol_hash($password) != $user->pass_indatabase_crypted)
232 | return false;*/
233 |
234 | // Authentication mode
235 | // disable googlerecaptcha
236 | $dolibarr_main_authentication = str_replace('googlerecaptcha','dolibarr', $dolibarr_main_authentication);
237 | if (empty($dolibarr_main_authentication))
238 | $dolibarr_main_authentication='http,dolibarr';
239 | $authmode = explode(',',$dolibarr_main_authentication);
240 | $entity = (GETPOST('entity','int') ? GETPOST('entity','int') : (!empty($conf->entity) ? $conf->entity : 1));
241 | if( ((float) DOL_VERSION < 11.0) && checkLoginPassEntity($username,$password,$entity,$authmode)!=$username
242 | ||
243 | ((float) DOL_VERSION >= 11.0) && checkLoginPassEntity($username,$password,$entity,$authmode,'dav')!=$username )
244 | {
245 | debug_log("Authentication failed 4 for user $username with pass ".str_pad('', strlen($password), '*'));
246 | return false;
247 | }
248 | debug_log("Authentication OK for user $username ");
249 | return true;
250 | });
251 |
252 | $authBackend->setRealm('Dolibarr');
253 |
254 | // The lock manager is reponsible for making sure users don't overwrite
255 | // each others changes.
256 | $lockBackend = new DAV\Locks\Backend\File($dolibarr_main_data_root.'/cdav/.locks');
257 |
258 | // Principals Backend
259 | $principalBackend = new DAVACL\PrincipalBackend\Dolibarr($user,$db);
260 |
261 | // CardDav & CalDav Backend
262 | $carddavBackend = new Sabre\CardDAV\Backend\Dolibarr($user,$db,$langs);
263 | $caldavBackend = new Sabre\CalDAV\Backend\Dolibarr($user,$db,$langs, $cdavLib);
264 |
265 | // Setting up the directory tree //
266 | $nodes = array(
267 | // /principals
268 | new DAVACL\PrincipalCollection($principalBackend),
269 | // /addressbook
270 | new \Sabre\CardDAV\AddressBookRoot($principalBackend, $carddavBackend),
271 | // /calendars
272 | new \Sabre\CalDAV\CalendarRoot($principalBackend, $caldavBackend),
273 | // / Public docs
274 | new DAV\FS\Directory($dolibarr_main_data_root. '/cdav/public')
275 | );
276 | // admin can access all dolibarr documents
277 | if($user->admin)
278 | $nodes[] = new DAV\FS\Directory($dolibarr_main_data_root);
279 |
280 | // The server object is responsible for making sense out of the WebDAV protocol
281 | $server = new DAV\Server($nodes);
282 |
283 | // If your server is not on your webroot, make sure the following line has the
284 | // correct information
285 | $server->setBaseUri(dol_buildpath('cdav/server.php', 1).'/');
286 |
287 |
288 | $server->addPlugin(new \Sabre\DAV\Auth\Plugin($authBackend));
289 | $server->addPlugin(new \Sabre\DAV\Locks\Plugin($lockBackend));
290 | $server->addPlugin(new \Sabre\DAV\Browser\Plugin());
291 | $server->addPlugin(new \Sabre\CardDAV\Plugin());
292 | $server->addPlugin(new \Sabre\CalDAV\Plugin());
293 | $DAVACL_plugin = new \Sabre\DAVACL\Plugin();
294 | $DAVACL_plugin->allowUnauthenticatedAccess = false;
295 | $server->addPlugin($DAVACL_plugin);
296 |
297 | debug_log("Ready : ".$user->login);
298 |
299 | // All we need to do now, is to fire up the server
300 | $server->exec();
301 |
302 | if (is_object($db)) $db->close();
303 |
--------------------------------------------------------------------------------
/sql/llx_actioncomm_cdav.sql:
--------------------------------------------------------------------------------
1 | -- ============================================================================
2 | -- Copyright (C) 2015 Jérôme ANDANSON
3 | --
4 | -- This program is free software; you can redistribute it and/or modify
5 | -- it under the terms of the GNU General Public License as published by
6 | -- the Free Software Foundation; either version 3 of the License, or
7 | -- (at your option) any later version.
8 | --
9 | -- This program is distributed in the hope that it will be useful,
10 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | -- GNU General Public License for more details.
13 | --
14 | -- You should have received a copy of the GNU General Public License
15 | -- along with this program. If not, see .
16 | --
17 | -- Table of "actioncomm_cdav" for cdav module
18 | -- ============================================================================
19 |
20 | CREATE TABLE IF NOT EXISTS `llx_actioncomm_cdav` (
21 | `fk_object` int(11) NOT NULL,
22 | `uuidext` varchar(255) NOT NULL,
23 | `sourceuid` varchar(255) NOT NULL,
24 | PRIMARY KEY (`fk_object`),
25 | KEY `uuidext` (`uuidext`)
26 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Storage of external UUID created by externals applications';
27 |
--------------------------------------------------------------------------------
/sql/update_001.sql:
--------------------------------------------------------------------------------
1 | -- ============================================================================
2 | -- Copyright (C) 2017 Jean-Pierre Morfin
3 | --
4 | -- This program is free software; you can redistribute it and/or modify
5 | -- it under the terms of the GNU General Public License as published by
6 | -- the Free Software Foundation; either version 3 of the License, or
7 | -- (at your option) any later version.
8 | --
9 | -- This program is distributed in the hope that it will be useful,
10 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | -- GNU General Public License for more details.
13 | --
14 | -- You should have received a copy of the GNU General Public License
15 | -- along with this program. If not, see .
16 | --
17 | -- add column sourceuid for cdav module
18 | -- ============================================================================
19 |
20 | ALTER TABLE `llx_actioncomm_cdav` ADD `sourceuid` VARCHAR(255) NOT NULL AFTER `uuidext`;
21 |
--------------------------------------------------------------------------------