Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
workflow.inc
1 <?php
17 require_once SQ_LIB_PATH.'/html_form/html_form.inc';
18 require_once DIRNAME(__FILE__).'/details.inc';
19 
39 function paintInlineWorkflow(Asset $owner, Backend_Outputter $o, Asset_Edit_Interface $ei)
40 {
41  $prefix = $owner->getPrefix();
42 
43  $wfm = $GLOBALS['SQ_SYSTEM']->getWorkflowManager();
44  $schemas = $wfm->getSchemas($owner->id, NULL, FALSE, TRUE);
45 
46  if (empty($schemas)) return FALSE;
47 
48  $direct = Array();
49  foreach ($schemas as $schemaid => $schema_info) {
50  $granted = $schema_info['granted'];
51  if (!isset($direct[$granted])) {
52  $direct[$granted] = Array();
53  }
54  $direct[$granted][] = $schemaid;
55  }
56  ksort($direct);
57 
58  $o->openSection(translate('workflow_schemas'));
59  $o->openField('&nbsp;');
60  ?>
61  <table class="sq-backend-table">
62  <tr>
63  <td class="sq-backend-table-header">
64  <?php echo translate('workflow_schema'); ?>
65  </td>
66  <td class="sq-backend-table-header" align="right">
67  <?php translate('access'); ?>
68  </td>
69  </tr>
70  <?php
71 
72  if (!empty($direct)) {
73  foreach ($direct as $granted => $schemaids) {
74  foreach ($schemaids as $schemaid) {
75  if ($schemaid) {
76  $schema_info = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(Array($schemaid), 'workflow_schema', FALSE);
77  if (empty($schema_info)) continue;
78  }
79  ?>
80  <tr>
81  <td class="sq-backend-table-cell">
82  <?php
83  echo get_asset_tag_line($schemaid);
84  ?>
85  </td>
86  <td class="sq-backend-table-cell" align="right">
87  <span style="color: <?php echo (($granted == '0') ? 'red' : 'green'); ?>; font-weight: bold;"><?php echo (($granted == '0') ? translate('denied') : translate('applied')) ?></span>
88  </td>
89  </tr>
90  <?php
91  }// end foreach data
92  }//end foreach inherited
93 
94  }// end if
95  ?></table><?php
96  $o->closeField();
97  $o->closeSection();
98 
99  return TRUE;
100 
101 }//end paintInlineWorkflow()
102 
103 
115 function paintWorkflow(Asset $owner, Backend_Outputter $o, Asset_Edit_Interface $ei, $keywords=NULL)
116 {
117  $wfm = $GLOBALS['SQ_SYSTEM']->getWorkflowManager();
118  $schemas = $wfm->getSchemas($owner->id);
119  $running_schemas = $wfm->getSchemas($owner->id, TRUE, TRUE);
120  $admin_access = $owner->adminAccess('workflow');
121 
122  // we only want to paint messages and commit buttons if the user can publish, so we must
123  // use workflow manager to see who these users are.
124  $publishers = $wfm->whoCanPublish($owner->id);
125  $current_userid = $GLOBALS['SQ_SYSTEM']->currentUserId();
126  $can_publish = in_array($current_userid, $publishers);
127 
128  $email_link_require_comment = FALSE; // Flag to display text when email link is used to approve or reject the workflow which requires comment.
129  $wf_email_link_updated = FALSE; // Flag to display text when the asset has been accepted or rejected.
130  $no_access_to_edit = FALSE; // Flag to display text when the user does not have permission to edit the asset.
131 
132  $available_statii = $owner->getAvailableStatii();
133 
134  if (isset($_REQUEST['asset_version'])) {
135  $link_asset_version = $_REQUEST['asset_version'];
136  $link_asset_version_wo_micro = substr($link_asset_version, 0, strrpos($link_asset_version, '.'));
137  $owner_version_wo_micro = substr($owner->version, 0, strrpos($owner->version, '.'));
138  }//end if
139 
140  if (isset($_REQUEST['workflow_link_action'])) {
141  if (isset($_REQUEST['asset_version']) && version_compare($link_asset_version_wo_micro,$owner_version_wo_micro )== 0 ) {
142  if ($can_publish) {
143  ksort($available_statii);
144  $new_status = NULL;
145  if ($_REQUEST['workflow_link_action'] == 'approve') {
146  foreach ($available_statii as $status_val => $desc) {
147  if ($owner->status <= $status_val) {
148  $new_status = $status_val;
149  break;
150  }//end if
151  }//end foreach
152  } else if ($_REQUEST['workflow_link_action'] == 'reject') {
153  foreach ($available_statii as $status_val => $desc) {
154  if ($owner->status >= $status_val) {
155  $new_status = $status_val;
156  break;
157  }//end if
158  }//end foreach
159  }
160 
161  if (!$wfm->requiresComment($owner->id, $GLOBALS['SQ_SYSTEM']->user->id)) {
162  $hh = $GLOBALS['SQ_SYSTEM']->getHipoHerder();
163  $vars = Array (
164  'assetid' => $owner->id,
165  'dependants_only' => TRUE,
166  );
167  if ($new_status != NULL) {
168  $vars['new_status'] = $new_status;
169  $hh->freestyleHipo('hipo_job_edit_status', $vars);
170  }//end if
171  $wf_email_link_updated = TRUE;
172  } else {
173  $email_link_require_comment = TRUE;
174  $default_selection = $_REQUEST['workflow_link_action'];
175  }
176  } else {
177  $no_access_to_edit = TRUE;
178  }//end else if
179  } else {
180  trigger_localised_error('CORE0280', E_USER_WARNING);
181  }
182 
183  }//end if
184 
185  // Get the running schema again now things has been changed.
186  $running_schemas = $wfm->getSchemas($owner->id, TRUE, TRUE);
187 
188  $root = $ei->findScreen('static_screen_workflow');
189  if (is_null($root)) return FALSE;
190 
191  $prefix = $owner->getPrefix();
192  $print_commit_button = FALSE;
193 
194  foreach ($root->section as $section) {
195 
196  // only do this if we are not painting a layout
197  if (is_null($keywords)) {
198  // if we are in limbo and this section is not to be printed in limbo - dont print it
199  if (SQ_IN_LIMBO && (!isset($section->attributes()->limbo_access) || (int)$section->attributes()->limbo_access == 0)) {
200  continue;
201  }
202  }
203 
204  $section_access = $ei->_getAccess($owner, $section, $prefix);
205  if (!($section_access & SQ_EI_READ)) {
206  continue;
207  }
208 
209  if (!is_null($keywords) && isset($keywords['sections'][strtolower(str_replace(' ', '_', $section->attributes()->name))])) {
210  ob_start();
211  }
212 
213  $o->openSection(array_get_index($section->attributes(), 'display_name', $section->attributes()->name));
214 
215  if (!($num_fields = count($section->children()))) {
216  continue;
217  }
218 
219  foreach ($section->field as $field) {
220 
221  switch (strtolower($field->attributes()->code)) {
222 
224 
225  case 'workflow_status_change' :
226 
227  // shouldn't be able to changes status, so don't show anything
228  if ((!$can_publish) && (!$admin_access)) {
229  if ($no_access_to_edit) {
230  trigger_localised_error('CORE0281', E_USER_WARNING, $_REQUEST['workflow_link_action']. ($_REQUEST['workflow_link_action'] == 'approve' ? 'd' : 'ed'));
231  }//end if
232  continue;
233  }
234 
235  if ($wf_email_link_updated) {
236  $o->openField('');
237  ob_start();
238  echo '<b class="sq-backend-warning">['.translate('workflow_email_link_updated', ($_REQUEST['workflow_link_action']. ($_REQUEST['workflow_link_action'] == 'approve' ? 'd' : 'ed'))).']</b>';
239  ob_end_flush();
240  $o->closeField();
241  }//end if
242 
243  if (!empty($running_schemas)) {
244  if ($email_link_require_comment) {
245  $o->openField('');
246  ob_start();
247  echo '<b class="sq-backend-warning">['.translate('email_link_require_comment').']</b>';
248  ob_end_flush();
249  $o->closeField();
250  }
251  $o->openField(translate('change_status'));
252  if (!is_null($keywords) && isset($keywords['fields']['workflow_status_change'])) {
253  ob_start();
254 
255  }
256  $available_statii = $owner->getAvailableStatii();
257  _paintStatusChange($owner, $o, $prefix, $available_statii, $email_link_require_comment ? $new_status : 0);
258  ?><span class="sq-backend-fineprint"><?php
259  if (!empty($available_statii)) {
260  echo '<br />'.translate('change_to_approve_or_reject');
261  } else {
262  echo translate('cannot_approve_or_reject');
263  }
264  ?></span><?php
265 
266  // if there is a keyword replacement for this, add it to the replacements
267  if (!is_null($keywords) && isset($keywords['fields']['workflow_status_change'])) {
268  $ei->_tmp['layout_keyword_replacements'][$keywords['fields']['workflow_status_change']] = ob_get_contents();
269  ob_end_flush();
270  }
271  $o->closeField();
272  }
273 
274  break;
275 
276  case 'workflow_log_message' :
277 
278  // shouldn't be able to changes status, so don't show anything
279  if ((!$can_publish) && (!$admin_access)) {
280  continue;
281  }
282  if (!empty($running_schemas)) {
283 
284  $o->openField(translate('log_message'));
285  if (!is_null($keywords) && isset($keywords['fields']['workflow_log_message'])) {
286  ob_start();
287  }
288 
289  text_area($prefix.'_workflow_new_log_message', '', 60, 6);
290  echo '<br/>';
291 
292  if ($wfm->requiresComment($owner->id, $GLOBALS['SQ_SYSTEM']->user->id)) {
293  echo translate('workflow_must_enter_reason_for_decision');
294  } else {
295  echo translate('workflow_may_enter_reason_for_decision');
296  }
297 
298  // if there is a keyword replacement for this, add it to the replacements
299  if (!is_null($keywords) && isset($keywords['fields']['workflow_log_message'])) {
300  $ei->_tmp['layout_keyword_replacements'][$keywords['fields']['workflow_log_message']] = ob_get_contents();
301  ob_end_flush();
302  }
303  $o->closeField();
304  }
305 
306  break;
307 
308  case 'workflow_status_commit' :
309 
310  // shouldn't be able to changes status, so don't show anything
311  if ((!$can_publish) && (!$admin_access)) {
312  continue;
313  }
314  if (!empty($running_schemas)) {
315 
316  $o->openField('');
317  if (!is_null($keywords) && isset($keywords['fields']['workflow_status_commit'])) {
318  ob_start();
319  }
320  $require_comment = $wfm->requiresComment($owner->id, $GLOBALS['SQ_SYSTEM']->user->id);
321  $button_js = 'submit_form()';
322  if ($require_comment) {
323  $button_js = "elt = document.getElementById('".$prefix."_workflow_new_log_message'); if (elt && elt.value.replace(".'/^\s+|\s+$/g'.", '').length == 0) alert(js_translate('must_enter_comment_error')); else submit_form();";
324  }
325  normal_button($prefix.'_workflow_status_update', SQ_CONF_COMMIT_BUTTON_TEXT, $button_js);
326 
327  // if there is a keyword replacement for this, add it to the replacements
328  if (!is_null($keywords) && isset($keywords['fields']['workflow_status_commit'])) {
329  $ei->_tmp['layout_keyword_replacements'][$keywords['fields']['workflow_status_commit']] = ob_get_contents();
330  ob_end_flush();
331  }
332  $o->closeField();
333  }
334 
335  break;
336 
337  case 'workflow_logs' :
338 
339  $o->openField(translate('workflow_logs'));
340  if (!is_null($keywords) && isset($keywords['fields']['workflow_logs'])) {
341  ob_start();
342  }
343 
344  $ms = $GLOBALS['SQ_SYSTEM']->getMessagingService();
345  $logs = $ms->getLogs('asset.workflow.log.*', Array('assetid' => $owner->id));
346 
347  $user_logs = $ms->getLogs('asset.workflow.userlog', Array('assetid' => $owner->id));
348  usort($logs, Array('Messaging_Service', 'sortMessages'));
349  usort($user_logs, Array('Messaging_Service', 'sortMessages'));
350 
351  if (!empty($user_logs) || !empty($logs)) {
352  ?>
353  <table class="sq-backend-table">
354  <tr>
355  <td class="sq-backend-table-header" nowrap width="120"><?php echo translate('log_time'); ?></td>
356  <td class="sq-backend-table-header" nowrap width="120"><?php echo translate('logged_by'); ?></td>
357  <td class="sq-backend-table-header" width="100%"><?php echo translate('message'); ?></td>
358  </tr>
359  <?php
360  if (!empty($user_logs)) {
361  ?>
362  <tr>
363  <td class="sq-backend-table-header" colspan="3"><?php echo translate('most_recent_user_log_message'); ?></td>
364  </tr>
365  <?php
366  for ($log_num = 0; $log_num < 4; $log_num++) {
367  if (!isset($user_logs[$log_num])) break;
368  $log_data = $user_logs[$log_num];
369  ?>
370  <tr>
371  <td class="sq-backend-table-cell" nowrap><?php echo ts_iso8601($log_data['sent']); ?></td>
372  <td class="sq-backend-table-cell" nowrap><?php echo $log_data['from_name']; ?></td>
373  <td class="sq-backend-table-cell" width="100%"><?php echo $log_data['body']; ?></td>
374  </tr>
375  <?php
376  }
377  }//end if there are user workflow logs
378 
379  if (!empty($logs)) {
380  ?>
381  <tr>
382  <td class="sq-backend-table-header" colspan="3"><?php echo translate('most_recent_system_workflow_message'); ?></td>
383  </tr>
384  <?php
385  for ($log_num = 0; $log_num < 4; $log_num++) {
386  if (!isset($logs[$log_num])) break;
387  $log_data = $logs[$log_num];
388  ?>
389  <tr>
390  <td class="sq-backend-table-cell" nowrap><?php echo ts_iso8601($log_data['sent']); ?></td>
391  <td class="sq-backend-table-cell" nowrap><?php echo $log_data['from_name']; ?></td>
392  <td class="sq-backend-table-cell" width="100%"><b><?php echo $log_data['subject']; ?></b><br/><?php echo $log_data['body']; ?></td>
393  </tr>
394  <?php
395  }
396  }//end if there are system workflow logs
397  ?>
398  <tr>
399  <td class="sq-backend-table-header" colspan="3" align="middle">
400  <a class="sq-backend-table-header" href="<?php echo $owner->getBackendHref('logs'); ?>&sq_backend_log_type=asset.workflow"><?php echo translate('view_all_workflow_logs'); ?></a>
401  </td>
402  </tr>
403  </table>
404  <?php
405 
406  }//end if there are workflow logs
407 
408  // if there is a keyword replacement for this, add it to the replacements
409  if (!is_null($keywords) && isset($keywords['fields']['workflow_logs'])) {
410  $ei->_tmp['layout_keyword_replacements'][$keywords['fields']['workflow_logs']] = ob_get_contents();
411  ob_end_flush();
412  }
413  $o->closeField();
414 
415  break;
416 
418 
419  case 'workflow_report' :
420 
421  if (!empty($running_schemas)) {
422 
423  $o->closeSection();
424 
425  if (!is_null($keywords) && isset($keywords['fields']['workflow_report'])) {
426  ob_start();
427  }
428 
429  $schema_workflows = $wfm->getSchemaWorkflows($owner->id);
430  foreach ($schema_workflows as $schemaid => $workflow) {
431 
432  if (!in_array($schemaid, $running_schemas)) continue;
433 
434  if (!isset($workflow['stream_name'])) $workflow['stream_name'] = translate('default_stream'); //Pre 3-26 systems
435  $schema_title = translate('running_workflow').' - '.$workflow['schema_name'].' - '.$workflow['stream_name'];
436  if (isset($workflow['complete']) && $workflow['complete']) {
437  $schema_title .= ' <span style="color:#008800">['.translate('completed').']</span>';
438  } else {
439  $schema_title .= ' <span style="color:#880000">['.translate('not_completed').']</span>';
440  }
441 
442  $o->openSection($schema_title);
443 
444  $o->openSection(translate('workflow_summary'));
445 
446  $o->openField(translate('workflow_started'));
447  echo $GLOBALS['SQ_SYSTEM']->datetime($workflow['started']);
448  $o->closeField();
449 
450  $o->openField(translate('time_running'));
451  require_once SQ_FUDGE_PATH.'/general/datetime.inc';
452  echo easy_time_total(time() - $workflow['started'], TRUE);
453  $o->closeField();
454  $o->closeSection();
455 
456  foreach ($workflow['steps'] as $stepid => $step_data) {
457  $section_title = "Step $stepid - ".$step_data['step_name'];
458 
459  if ($step_data['expired']) {
460  $section_title .= ' <span style="color:#FF9900">['.translate('escalated').']</span>';
461  } else {
462  if ($step_data['completed']) {
463  $section_title .= ' <span style="color:#008800">['.translate('completed').']</span>';
464  } else {
465  $section_title .= ' <span style="color:#880000">['.translate('not_completed').']</span>';
466  }
467  }
468  $o->openSection($section_title);
469 
470  if ($step_data['started']) {
471  $o->openField(translate('step_duration'));
472  echo $GLOBALS['SQ_SYSTEM']->datetime($step_data['started']);
473  echo ' - ';
474  if ($step_data['completed']) {
475  echo $GLOBALS['SQ_SYSTEM']->datetime($step_data['completed']);
476  } else {
477  echo '??';
478  }
479  echo ' (<i>';
480  require_once SQ_FUDGE_PATH.'/general/datetime.inc';
481  if ($step_data['completed']) {
482  echo easy_time_total($step_data['completed'] - $step_data['started'], TRUE);
483  } else {
484  echo easy_time_total(time() - $step_data['started'], TRUE);
485  }
486  echo '</i>)';
487  $o->closeField();
488  if ($step_data['expiry_time'] > 0) {
489  $o->openField(translate('expiry_time'));
490  $expiry_time = $step_data['started'] + $step_data['expiry_time'];
491  echo $GLOBALS['SQ_SYSTEM']->datetime($expiry_time);
492  echo ' (<i> ';
493  echo easy_time_total($expiry_time - time(), TRUE);
494  echo ' </i>)';
495  $o->closeField();
496  }
497  $o->openField(translate('automatically_escalate'));
498  if ($step_data['escalate']) {
499  echo translate('yes');
500  } else {
501  echo translate('no');
502  }
503  $o->closeField();
504  }//end if
505  $o->openField(translate('step_logic'));
506  if (isset($wfm->_valid_cond_logic[$step_data['logic']])) {
507  // a special type of logic statement
508  $step_logic = $step_data['logic'];
509  $step_logic_num = '';
510  } else {
511  if ($step_data['logic'] != 'all') {
512  list($step_logic, $step_logic_num) = explode(' ', $step_data['logic']);
513  } else {
514  $step_logic = 'all';
515  $step_logic_num = '';
516  }
517  }
518 
519  echo '<i>'.$wfm->_valid_step_logic[$step_logic];
520  if ($step_logic_num) {
521  echo " $step_logic_num condition".(($step_logic_num > 1) ? 's' : '').' must be met</i>';
522  }
523  $o->closeField();
524 
525  $o->openField(translate('conditions'));
526 
527  $has_conds = FALSE;
528  ob_start();
529  ?>
530  <table class="sq-backend-table">
531  <tr>
532  <td class="sq-backend-table-header">&nbsp;</td>
533  <td class="sq-backend-table-header" width="270"><b><?php echo translate('group_logic'); ?></b></td>
534  <td align="center" width="100" class="sq-backend-table-header"><b><?php echo translate('complete_question'); ?></b></td>
535  </tr>
536  <?php
537  foreach ($step_data['conditions'] as $pub => $cond_data) {
538  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($pub);
539  if (!$asset->id) continue;
540  ?>
541  <tr>
542  <td class="sq-backend-table-cell"><?php echo get_asset_tag_line($pub); ?></td>
543  <td class="sq-backend-table-cell">
544  <?php
545  if (isset($wfm->_valid_cond_logic[$cond_data['logic']])) {
546  // a special type of logic statement
547  $cond_logic = $cond_data['logic'];
548  $cond_logic_num = '';
549  } else {
550  if ($cond_data['logic'] != 'all') {
551  list($cond_logic, $cond_logic_num) = explode(' ', $cond_data['logic']);
552  } else {
553  $cond_logic = 'all';
554  $cond_logic_num = '';
555  }
556  }
557 
558  if ($asset instanceof User) {
559  echo '&nbsp;';
560  } else {
561  echo '<i>'.$wfm->_valid_cond_logic[$cond_logic];
562  if ($cond_logic_num) {
563  echo " $cond_logic_num group member".(($cond_logic_num > 1) ? 's' : '').' must approve</i>';
564  }
565  }
566 
567  ?></td>
568 
569  <td align="center" class="sq-backend-table-cell">
570  <?php
571  if (isset($cond_data['complete']) && $cond_data['complete']) {
572  echo '<span style="color:#008800"><b>'.translate('yes').'</b></span>';
573  } else {
574  // do some extra checking
575  if ($asset instanceof User) {
576  echo ((isset($cond_data['published_by'][$asset->id])) ? '<span style="color:#008800"><b>'.translate('yes').'</b></span>' : '&nbsp;');
577  } else {
578  if ($cond_logic_num) {
579  $user_count = $cond_logic_num;
580  } else {
581  $user_count = count($GLOBALS['SQ_SYSTEM']->am->getChildren($asset->id, Array('user'), FALSE));
582  }
583 
584  echo '<span style="color:#';
585  if (count($cond_data['published_by']) >= $user_count) {
586  echo '008800';
587  } else {
588  echo '880000';
589  }
590  echo '"><b>';
591  echo count($cond_data['published_by']).' of '.$user_count;
592  echo '</b></span>';
593  }
594  }
595  ?>
596  </td>
597  </tr>
598 
599  <?php
600  $has_conds = TRUE;
601  }//end foreach
602 
603  if (!$has_conds) {
604  ob_end_clean();
605  echo translate('none');
606  } else {
607  ob_end_flush();
608  ?></table><?php
609  }
610 
611  $o->closeField();
612 
613  // escalation steps
614  if ($step_data['expired']) {
615  $o->openField('Escalation Steps');
616  $esc_address = Array();
617  foreach ($step_data['escalation_steps'] as $esc_stepid => $esc_step_data) {
618  $esc_step_address = Array($stepid);
619  $esc_step_address[] = $esc_stepid;
620 
621  _paintWorkflowStep($owner, $o, $ei, $workflow, $esc_step_address);
622  }
623  $o->closeField();
624  } //end if expiry automatic
625  $o->closeSection();
626  }//end foreach step
627  $o->closeSection();
628  }//end foreach
629 
630  // if there is a keyword replacement for this, add it to the replacements
631  if (!is_null($keywords) && isset($keywords['fields']['workflow_report'])) {
632  $ei->_tmp['layout_keyword_replacements'][$keywords['fields']['workflow_report']] = ob_get_contents();
633  ob_end_flush();
634  }
635 
636  $o->openSection();
637 
638  } else {
639  $o->openField(translate('workflow_status'));
640  if (!is_null($keywords) && isset($keywords['fields']['workflow_report'])) {
641  ob_start();
642  }
643 
644  echo translate('workflow_not_running');
645 
646  // if there is a keyword replacement for this, add it to the replacements
647  if (!is_null($keywords) && isset($keywords['fields']['workflow_report'])) {
648  $ei->_tmp['layout_keyword_replacements'][$keywords['fields']['workflow_report']] = ob_get_contents();
649  ob_end_flush();
650  }
651  $o->closeField();
652  }
653 
654  break;
655 
657 
658  case 'workflow_metadata_warning' :
659 
660  // lets show some workflow warnings about metadata if we need to
661  if ($owner->status & SQ_SC_STATUS_PENDING) {
662  $mm = $GLOBALS['SQ_SYSTEM']->getMetadataManager();
663  if ($mm->allowsMetadata($owner->id)) {
664  $m_complete = $mm->requiredFieldsComplete($owner->id);
665  if (!$m_complete) {
666  $o->openField('<span class="sq-backend-warning"><b>'.ucfirst(strtolower(translate('warning'))).'</b></span>');
667  if (!is_null($keywords) && isset($keywords['fields']['workflow_metadata_warning'])) {
668  ob_start();
669  }
670 
671  ?>
672  <p class="sq-backend-data">
673  <span class="sq-backend-warning">
674  <b><?php echo translate('metadata_in_approval_requires_fields_completion', htmlspecialchars($owner->name, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET)); ?></b>
675  </span>
676  <?php echo translate('metadata_fields_only_completed_by_administrator', htmlspecialchars($owner->name, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET), '<a href="'.$owner->getBackendHref('metadata').'">'.translate('metadata_screen').'</a>'); ?>
677  </p>
678  <?php
679 
680  // if there is a keyword replacement for this, add it to the replacements
681  if (!is_null($keywords) && isset($keywords['fields']['workflow_metadata_warning'])) {
682  $ei->_tmp['layout_keyword_replacements'][$keywords['fields']['workflow_metadata_warning']] = ob_get_contents();
683  ob_end_flush();
684  }
685  $o->closeField();
686  }
687  }
688  }
689 
690  break;
691 
693 
694  case 'workflow_schemas' :
695 
696  $schemas = $wfm->getAssetSchemaInfo($owner->id);
697 
698  $direct = Array();
699  foreach ($schemas as $schemaid => $schema_info) {
700  $granted = $schema_info['granted'];
701  if (!isset($direct[$granted])) {
702  $direct[$granted] = Array();
703  }
704  $direct[$granted][$schemaid] = $schema_info;
705  }
706  ksort($direct);
707 
708  $o->openSection('Existing Schemas');
709  $o->openRaw();
710  if (!is_null($keywords) && isset($keywords['fields']['workflow_schemas'])) {
711  ob_start();
712  }
713 
714  if (empty($direct)) {
715  echo translate('no_workflow_schemas');
716  } else {
717  foreach ($direct as $granted => $schema_list) {
718  ?>
719  <table class="sq-backend-table">
720  <tr>
721  <td class="sq-backend-table-header">
722  <span style="color: <?php echo (($granted == '0') ? 'red' : 'green'); ?>"><?php echo (($granted == '0') ? translate('denied') : translate('applied')) ?></span>
723  </td>
724  <td align="center" width="100" class="sq-backend-table-header">
725  <?php echo translate('cascade_question'); ?>
726  </td>
727  <?php
728  if ($admin_access && $wfm->isWorkflowComplete($owner->id)) {
729  ?><td align="center" width="100" class="sq-backend-table-header" style="font-weight: bold;"><?php echo translate('delete_question'); ?></td><?php
730  }
731  ?>
732  </tr>
733  <?php
734  foreach ($schema_list as $schemaid => $schema_detail) {
735  if ($schemaid) {
736  $schema_info = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(Array($schemaid), 'workflow_schema', FALSE);
737  if (empty($schema_info)) continue;
738  }
739  ?>
740  <tr>
741  <td class="sq-backend-table-cell">
742  <?php
743  echo get_asset_tag_line($schemaid);
744  ?>
745  </td>
746  <td align="center" width="100" class="sq-backend-table-cell">
747  <?php if ($admin_access && $wfm->isWorkflowComplete($owner->id)) {
748  check_box($prefix.'_workflow[cascades]['.$schemaid.']', 1, $schema_detail['cascades']);
749  } else {
750  ?><img src="<?php echo sq_web_path('lib'); ?>/web/images/<?php echo ($schema_detail['cascades'] ? 'tick' : 'cross'); ?>.gif" width="15" height="15" /><?php
751  }
752  ?>
753  </td>
754  <?php
755  if ($admin_access && $wfm->isWorkflowComplete($owner->id)) {
756  ?><td align="center" width="100" class="sq-backend-table-cell"><?php
757  check_box($prefix.'_workflow[delete]['.$schemaid.']');
758  ?></td><?php
759  }
760  ?>
761  </tr>
762  <?php
763  }// end foreach data
764  ?>
765  </table>
766  <br>
767  <?php
768  }//end foreach inherited
769 
770  }//end else
771 
772  // if there is a keyword replacement for this, add it to the replacements
773  if (!is_null($keywords) && isset($keywords['fields']['workflow_schemas'])) {
774  $ei->_tmp['layout_keyword_replacements'][$keywords['fields']['workflow_schemas']] = ob_get_contents();
775  ob_end_flush();
776  }
777 
778  $o->closeRaw();
779  $o->sectionNote('The "Cascade ?" option determines whether new children of this asset will automatically have the schema cascaded to them. If this setting is changed, existing non-dependant children will NOT be affected. If you want to apply a schema to existing children where they have not been before, please do a Manual Cascade after toggling this setting on.');
780  $o->closeSection();
781 
782  break;
783 
785 
786  case 'workflow_add_schemas' :
787 
788  if ($admin_access && empty($running_schemas)) {
789  $o->openSection('Add New Schema');
790 
791  if (!is_null($keywords) && isset($keywords['fields']['workflow_add_schemas'])) {
792  ob_start();
793  }
794 
795  $o->openField('Select Schema', 'new_line');
796  combo_box($prefix.'_workflow[new][granted]', Array('' => '', '1' => translate('apply'), '0' => translate('deny')), FALSE, '');
797  echo ' '.translate('workflow_schema').' ';
798  asset_finder($prefix.'_workflow[new][schemaid]', 0, Array('workflow_schema' => 'D'), 'sq_sidenav', FALSE, 'null', Array('clear'));
799  $o->closeField();
800 
801  if (is_null($keywords) || isset($keywords['fields']['workflow_add_schemas'])) {
802  $print_commit_button = TRUE;
803  }
804 
805  // if there is a keyword replacement for this, add it to the replacements
806  if (!is_null($keywords) && isset($keywords['fields']['workflow_add_schemas'])) {
807  $ei->_tmp['layout_keyword_replacements'][$keywords['fields']['workflow_add_schemas']] = ob_get_contents();
808  ob_end_flush();
809  }
810 
811  $o->closeField();
812 
813  $o->openField(translate('cascade_question'), 'new_line');
814  check_box($prefix.'_workflow[new][cascades]', 1, TRUE);
815  ?> Automatically cascade this schema to new children<?php
816  $o->note('If unchecked, the schema will be applied or denied only to dependants of this asset, regardless of the Cascade Changes settings below. It will also not apply the workflow to any asset that becomes a new child of this asset (through creating a new asset, or moving an existing one, or creating a new link from one). This setting can be toggled after being applied.');
817  $o->closeField();
818 
819  $o->closeSection();
820  }
821 
822  break;
823 
825 
826  case 'workflow_cascade_options' :
827 
828  $o->openField('');
829  if (!is_null($keywords) && isset($keywords['fields']['workflow_cascade_options'])) {
830  ob_start();
831  }
832 
833  if ($admin_access && empty($running_schemas)) {
834  $kiddies = $GLOBALS['SQ_SYSTEM']->am->getChildren($owner->id);
835  if (count($kiddies)) {
836  echo translate('action_affects_assets_below_this', count($kiddies), htmlspecialchars($owner->name, ENT_COMPAT, SQ_CONF_DEFAULT_CHARACTER_SET)).'<br /><br />';
837 
838  check_box($prefix.'_workflow[cascade_changes]', '1', TRUE);
839  echo ' ';
840  label(translate('cascade_schema_changes'), $prefix.'_workflow[cascade_changes]');
841  echo '<br/>';
842  check_box($prefix.'_workflow[manual_cascade]');
843  echo ' ';
844  label(translate('manually_cascade_schema'), $prefix.'_workflow[manual_cascade]');
845 
846  } else {
847  echo translate('no_children_to_cascade_workflow');
848  }
849  } else if ($admin_access) {
850  echo translate('cannot_cascade_while_workflow_running');
851  } else {
852  echo translate('no_access_to_cascade_workflow');
853  }
854 
855  // if there is a keyword replacement for this, add it to the replacements
856  if (!is_null($keywords) && isset($keywords['fields']['workflow_cascade_options'])) {
857  $ei->_tmp['layout_keyword_replacements'][$keywords['fields']['workflow_cascade_options']] = ob_get_contents();
858  ob_end_flush();
859  }
860  $o->closeField();
861 
862  break;
863 
864  }//end switch
865 
866  $note = (string) $field->note;
867  if (!empty($note)) {
868  $o->note($note);
869  }
870 
871  }//end for
872 
873  $o->closeSection();
874 
875  if (!is_null($keywords) && isset($keywords['sections'][strtolower(str_replace(' ', '_', $section->attributes()->name))])) {
876  $ei->_tmp['layout_keyword_replacements'][$keywords['sections'][strtolower(str_replace(' ', '_', $section->attributes()->name))]] = ob_get_contents();
877  ob_end_flush();
878  }
879 
880  }//end for
881 
882  return $print_commit_button;
883 
884 }//end paintWorkflow()
885 
886 
898 function processWorkflow(Asset $owner, Backend_Outputter $o, Asset_Edit_Interface $ei)
899 {
900  $updated = FALSE;
901  $prefix = $owner->getPrefix();
902 
903  // process a status change on this screen if workflow is running
904  $wfm = $GLOBALS['SQ_SYSTEM']->getWorkflowManager();
905  $running_schemas = $wfm->getSchemas($owner->id, TRUE, TRUE);
906 
907  // has a message been entered?
908  $message_body = '';
909  if (isset($_REQUEST[$prefix.'_workflow_new_log_message'])) {
910  $message_body = trim($_REQUEST[$prefix.'_workflow_new_log_message']);
911  }
912 
913  // are comments required?
914  $require_comment = $wfm->requiresComment($owner->id, $GLOBALS['SQ_SYSTEM']->user->id);
915 
916  // process any messages that may have been submitted
917  if (!empty($message_body)) {
918  $ms = $GLOBALS['SQ_SYSTEM']->getMessagingService();
919  $msg_reps = Array(
920  'message' => $message_body,
921  );
922  $message = $ms->newMessage(Array(), 'asset.workflow.userlog', $msg_reps);
923  $message->parameters['assetid'] = $owner->id;
924  $message->parameters['version'] = substr($owner->version, 0, strrpos($owner->version, '.'));
925  $message->send();
926  $updated = TRUE;
927  }
928 
929  // process the status, but only if the required comment conditions are met
930  if (!empty($running_schemas) && !($require_comment && empty($message_body))) {
931  _processStatusChange($owner, $o, $prefix);
932  $updated = TRUE;
933  }
934 
935  // if we dont have admin access, dont process anything
936  if (!$owner->adminAccess('workflow')) return $updated;
937 
938  if (!isset($_POST[$prefix.'_workflow'])) {
939  return $updated;
940  }
941 
942  $wfm = $GLOBALS['SQ_SYSTEM']->getWorkflowManager();
943 
944  // are we cascading these schema changes to our children?
945  $cascade_changes = FALSE;
946  if (isset($_POST[$prefix.'_workflow']['cascade_changes']) && $_POST[$prefix.'_workflow']['cascade_changes']) {
947  $cascade_changes = TRUE;
948  }
949 
950  $schema_vars = Array();
951  $post_data = $_POST[$prefix.'_workflow'];
952  $depandants = $GLOBALS['SQ_SYSTEM']->am->getDependantChildren($owner->id);
953  $has_dependants = !empty($depandants);
954 
955  // apply a schema
956  if (!empty($post_data['new']['schemaid']['assetid'])) {
957  if (!isset($post_data['new']['granted']) || $post_data['new']['granted'] == '') {
958  trigger_localised_error('SYS0268', E_USER_NOTICE, $post_data['new']['schemaid']['assetid']);
959  } else {
960 
961  // Cascade changes to lower assets if "cascade" is set
962  // UNLESS there are dependents
963  if (($cascade_changes && isset($post_data['new']['cascades'])) || $has_dependants) {
964  // cascading access of some kind, so queue it up for the HIPO
965  $schema_vars[] = Array(
966  'assetids' => Array($owner->id),
967  'granted' => (int)$post_data['new']['granted'],
968  'schemaid' => (int)$post_data['new']['schemaid']['assetid'],
969  'cascades' => (int)isset($post_data['new']['cascades']) ? 1 : 0,
970  'previous_access' => NULL,
971  'dependants_only' => !($cascade_changes && isset($post_data['new']['cascades'])) && $has_dependants,
972  );
973  } else {
974  // lets do this ourselves
975  if (!$wfm->setSchema($owner->id, (int)$post_data['new']['schemaid']['assetid'], (int)$post_data['new']['granted'], (isset($post_data['new']['cascades']) ? 1 : 0))) {
976  return $updated;
977  }
978  }
979  }
980  }
981 
982  // revoke [deny] schema (apply or deny can be revoked)
983  if (!empty($post_data['delete'])) {
984  foreach ($post_data['delete'] as $schemaid => $on) {
985  $schemaid = (int)$schemaid;
986  $schema_info = $wfm->getAssetSchemaInfo($owner->id, $schemaid);
987  if (($cascade_changes && $schema_info['cascades']) || $has_dependants) {
988  $current_access = $schema_info['granted'];
989  $schema_vars[] = Array(
990  'assetids' => Array($owner->id),
991  'granted' => -1,
992  'schemaid' => $schemaid,
993  'cascades' => $cascade_changes,
994  'previous_access' => $current_access,
995  'dependants_only' => !($cascade_changes && $schema_info['cascades']) && $has_dependants,
996  );
997  } else {
998  if (!$wfm->deleteSchema($owner->id, $schemaid)) {
999  return $updated;
1000  }
1001  }
1002  }
1003  }
1004 
1005  // Set cascades here
1006  $schemas = $wfm->getAssetSchemaInfo($owner->id);
1007  foreach ($schemas as $schemaid => $schema_info) {
1008  $cascades = isset($post_data['cascades'][$schemaid]);
1009  if ((boolean)$cascades != (boolean)$schema_info['cascades']) {
1010  if ($has_dependants) {
1011  $current_access = $schema_info['granted'];
1012  $schema_vars[] = Array(
1013  'assetids' => Array($owner->id),
1014  'granted' => $current_access,
1015  'schemaid' => $schemaid,
1016  'cascades' => $cascades,
1017  'previous_access' => NULL,
1018  'dependants_only' => 1,
1019  );
1020  } else {
1021  if (!$wfm->setSchema($owner->id, (int)$schemaid, (int)$schema_info['granted'], (int)$cascades)) {
1022  return FALSE;
1023  }
1024  }
1025  }
1026  }
1027 
1028  if (isset($_POST[$prefix.'_workflow']['manual_cascade']) && $_POST[$prefix.'_workflow']['manual_cascade']) {
1029  $schemas = $wfm->getAssetSchemaInfo($owner->id, NULL, TRUE);
1030  foreach ($schemas as $schemaid => $schema_info) {
1031  $schema_vars[] = Array(
1032  'assetids' => Array($owner->id),
1033  'granted' => $schema_info['granted'],
1034  'cascades' => TRUE,
1035  'schemaid' => $schemaid,
1036  'previous_access' => NULL,
1037  );
1038  }
1039  }
1040 
1041 
1042  if (!empty($schema_vars)) {
1043  $hh = $GLOBALS['SQ_SYSTEM']->getHipoHerder();
1044  $vars = Array(
1045  'schema_changes' => $schema_vars,
1046  );
1047  $hh->queueHipo('hipo_job_edit_workflow_schemas', $vars);
1048  }
1049 
1050  return TRUE;
1051 
1052 }//end processWorkflow()
1053 
1054 
1067 function _paintWorkflowStep(Asset $owner, Backend_Outputter $o, Asset_Edit_Interface $ei, array &$workflow, array $step_address)
1068 {
1069  $wfm = $GLOBALS['SQ_SYSTEM']->getWorkflowManager();
1070  $step_data =& $wfm->getCurrentStep($workflow, $step_address); // need by ref
1071  $section_title = 'Step '.implode('.',$step_address).' - '.$step_data['step_name'];
1072 
1073  if ($step_data['expired']) {
1074  $section_title .= ' <span style="color:#FF9900">['.translate('escalated').']</span>';
1075  } else {
1076  if ($step_data['completed']) {
1077  $section_title .= ' <span style="color:#008800">['.translate('completed').']</span>';
1078  } else {
1079  $section_title .= ' <span style="color:#880000">['.translate('not_completed').']</span>';
1080  }
1081  }
1082 
1083  $o->openSection($section_title);
1084  if ($step_data['started']) {
1085  $o->openField(translate('step_duration'));
1086  echo $GLOBALS['SQ_SYSTEM']->datetime($step_data['started']);
1087  echo ' - ';
1088  if ($step_data['completed']) {
1089  echo $GLOBALS['SQ_SYSTEM']->datetime($step_data['completed']);
1090  } else {
1091  echo '??';
1092  }
1093  echo ' (<i>';
1094  require_once SQ_FUDGE_PATH.'/general/datetime.inc';
1095  if ($step_data['completed']) {
1096  echo easy_time_total($step_data['completed'] - $step_data['started'], TRUE);
1097  } else {
1098  echo easy_time_total(time() - $step_data['started'], TRUE);
1099  }
1100  echo '</i>)';
1101  $o->closeField();
1102  if ($step_data['expiry_time'] > 0) {
1103  $o->openField(translate('expiry_time'));
1104  $expiry_time = $step_data['started'] + $step_data['expiry_time'];
1105  echo $GLOBALS['SQ_SYSTEM']->datetime($expiry_time);
1106  echo ' (<i> ';
1107  echo easy_time_total($expiry_time - time(), TRUE);
1108  echo ' </i>)';
1109 
1110  $o->closeField();
1111  $o->openField(translate('automatically_escalate'));
1112  if ($step_data['escalate']) {
1113  echo translate('yes');
1114  } else {
1115  echo translate('no');
1116  }
1117  $o->closeField();
1118  }
1119  }//end if started
1120 
1121 
1122  $o->openField(translate('step_logic'));
1123  if (isset($wfm->_valid_cond_logic[$step_data['logic']])) {
1124  // a special type of logic statement
1125  $step_logic = $step_data['logic'];
1126  $step_logic_num = '';
1127  } else {
1128  if ($step_data['logic'] != 'all') {
1129  list($step_logic, $step_logic_num) = explode(' ', $step_data['logic']);
1130  } else {
1131  $step_logic = 'all';
1132  $step_logic_num = '';
1133  }
1134  }
1135 
1136  echo '<i>'.$wfm->_valid_step_logic[$step_logic];
1137  if ($step_logic_num) {
1138  echo " $step_logic_num condition".(($step_logic_num > 1) ? 's' : '').' must be met</i>';
1139  }
1140  $o->closeField();
1141 
1142  $o->openField(translate('conditions'));
1143 
1144  $has_conds = FALSE;
1145  ob_start();
1146  ?>
1147  <table class="sq-backend-table">
1148  <tr>
1149  <td class="sq-backend-table-header">&nbsp;</td>
1150  <td class="sq-backend-table-header" width="270"><b><?php echo translate('group_logic'); ?></b></td>
1151  <td align="center" width="100" class="sq-backend-table-header"><b><?php echo translate('complete_question'); ?></b></td>
1152  </tr>
1153  <?php
1154  foreach ($step_data['conditions'] as $pub => $cond_data) {
1155  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($pub);
1156  if (!$asset->id) continue;
1157  ?>
1158  <tr>
1159  <td class="sq-backend-table-cell"><?php echo get_asset_tag_line($pub); ?></td>
1160  <td class="sq-backend-table-cell">
1161  <?php
1162  if (isset($wfm->_valid_cond_logic[$cond_data['logic']])) {
1163  // a special type of logic statement
1164  $cond_logic = $cond_data['logic'];
1165  $cond_logic_num = '';
1166  } else {
1167  if ($cond_data['logic'] != 'all') {
1168  list($cond_logic, $cond_logic_num) = explode(' ', $cond_data['logic']);
1169  } else {
1170  $cond_logic = 'all';
1171  $cond_logic_num = '';
1172  }
1173  }
1174 
1175  if ($asset instanceof User) {
1176  echo '&nbsp;';
1177  } else {
1178  echo '<i>'.$wfm->_valid_cond_logic[$cond_logic];
1179  if ($cond_logic_num) {
1180  echo " $cond_logic_num group member".(($cond_logic_num > 1) ? 's' : '').' must approve</i>';
1181  }
1182  }
1183 
1184  ?></td>
1185 
1186  <td align="center" class="sq-backend-table-cell">
1187  <?php
1188  if (isset($cond_data['complete']) && $cond_data['complete']) {
1189  echo '<span style="color:#008800"><b>'.translate('yes').'</b></span>';
1190  } else {
1191  // do some extra checking
1192  if ($asset instanceof User) {
1193  echo ((isset($cond_data['published_by'][$asset->id])) ? '<span style="color:#008800"><b>'.translate('yes').'</b></span>' : '&nbsp;');
1194  } else {
1195  if ($cond_logic_num) {
1196  $user_count = $cond_logic_num;
1197  } else {
1198  $user_count = count($GLOBALS['SQ_SYSTEM']->am->getChildren($asset->id, Array('user'), FALSE));
1199  }
1200 
1201  echo '<span style="color:#';
1202  if (count($cond_data['published_by']) >= $user_count) {
1203  echo '008800';
1204  } else {
1205  echo '880000';
1206  }
1207  echo '"><b>';
1208  echo count($cond_data['published_by']).' of '.$user_count;
1209  echo '</b></span>';
1210  }
1211  }
1212  ?>
1213  </td>
1214  </tr>
1215 
1216  <?php
1217  $has_conds = TRUE;
1218  }//end foreach
1219 
1220  if (!$has_conds) {
1221  ob_end_clean();
1222  echo translate('none');
1223  } else {
1224  ob_end_flush();
1225  ?></table><?php
1226  }
1227 
1228  $o->closeField();
1229 
1230  // escalation steps
1231  if ($step_data['expired']) {
1232  $o->openField('Escalation Steps');
1233  foreach ($step_data['escalation_steps'] as $esc_stepid => $esc_step) {
1234  $esc_step_address = $step_address;
1235  $esc_step_address[] = $esc_stepid;
1236  _paintWorkflowStep($owner, $o, $ei, $workflow, $esc_step_address);
1237  }
1238  $o->closeField();
1239  }
1240  $o->closeSection();
1241 
1242 }//end _paintWorkflowStep()
1243 
1244 
1245 ?>