1<?php
2# MantisBT - A PHP based bugtracking system
3
4# MantisBT 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 2 of the License, or
7# (at your option) any later version.
8#
9# MantisBT 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 MantisBT.  If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Workflow Configuration Page
19 *
20 * @package MantisBT
21 * @copyright Copyright 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
22 * @copyright Copyright 2002  MantisBT Team - mantisbt-dev@lists.sourceforge.net
23 * @link http://www.mantisbt.org
24 *
25 * @uses core.php
26 * @uses authentication_api.php
27 * @uses config_api.php
28 * @uses constant_inc.php
29 * @uses current_user_api.php
30 * @uses form_api.php
31 * @uses helper_api.php
32 * @uses html_api.php
33 * @uses lang_api.php
34 * @uses print_api.php
35 * @uses project_api.php
36 * @uses string_api.php
37 * @uses workflow_api.php
38 */
39
40require_once( 'core.php' );
41require_api( 'authentication_api.php' );
42require_api( 'config_api.php' );
43require_api( 'constant_inc.php' );
44require_api( 'current_user_api.php' );
45require_api( 'form_api.php' );
46require_api( 'helper_api.php' );
47require_api( 'html_api.php' );
48require_api( 'lang_api.php' );
49require_api( 'print_api.php' );
50require_api( 'project_api.php' );
51require_api( 'string_api.php' );
52require_api( 'workflow_api.php' );
53
54auth_reauthenticate();
55
56layout_page_header( lang_get( 'manage_workflow_config' ) );
57
58layout_page_begin( 'manage_overview_page.php' );
59
60print_manage_menu( PAGE_CONFIG_DEFAULT );
61print_manage_config_menu( 'manage_config_workflow_page.php' );
62
63# CSS class names for overrides color coding
64define( 'COLOR_GLOBAL', 'color-global' );
65define( 'COLOR_PROJECT', 'color-project' );
66
67$g_access = current_user_get_access_level();
68$t_project = helper_get_current_project();
69$g_can_change_workflow = ( $g_access >= config_get_access( 'status_enum_workflow' ) );
70$g_can_change_flags = $g_can_change_workflow;
71$g_overrides = array();
72
73/**
74 * Set overrides
75 * @param string $p_config     Configuration value.
76 * @param bool   $p_can_change True if user has access level to change config
77 * @param string $p_color      CSS class name
78 * @return void
79 */
80function set_overrides( $p_config, $p_can_change, $p_color ) {
81	global $g_overrides;
82
83	if( !$p_can_change ) {
84		return;
85	}
86
87	$t_project = helper_get_current_project();
88	if(    $t_project == ALL_PROJECTS && $p_color == COLOR_GLOBAL
89		|| $t_project != ALL_PROJECTS && $p_color == COLOR_PROJECT
90	) {
91		$g_overrides[$p_config] = $p_config;
92	}
93}
94
95/**
96 * Returns a string to define the background color attribute depending
97 * on the level where it's overridden
98 * @param integer $p_level_file    Config file's access level.
99 * @param integer $p_level_global  All projects' access level.
100 * @param integer $p_level_project Current project's access level.
101 * @return string class name or '' if no override.
102 */
103function set_color_override( $p_level_file, $p_level_global, $p_level_project ) {
104	if( $p_level_project != $p_level_global ) {
105		$t_color = COLOR_PROJECT;
106	} else if( $p_level_global != $p_level_file ) {
107		$t_color = COLOR_GLOBAL;
108	} else {
109		$t_color = '';
110	}
111
112	return $t_color;
113}
114
115
116/**
117 * Get the value associated with the specific action and flag.
118 * @param integer $p_from_status_id From status id.
119 * @param integer $p_to_status_id   To status id.
120 * @return string
121 */
122function show_flag( $p_from_status_id, $p_to_status_id ) {
123	global $g_can_change_workflow,
124		$g_file_workflow, $g_global_workflow, $g_project_workflow,
125		$t_resolved_status, $t_reopen_status, $t_reopen_label;
126	if( $p_from_status_id <> $p_to_status_id ) {
127		$t_file = isset( $g_file_workflow['exit'][$p_from_status_id][$p_to_status_id] ) ? 1 : 0;
128		$t_global = isset( $g_global_workflow['exit'][$p_from_status_id][$p_to_status_id] ) ? 1 : 0;
129		$t_project = isset( $g_project_workflow['exit'][$p_from_status_id][$p_to_status_id] ) ? 1 : 0;
130
131		$t_color = set_color_override( $t_file, $t_global, $t_project );
132		set_overrides( 'status_enum_workflow', $g_can_change_workflow, $t_color );
133		$t_value = '<td class="center ' . $t_color . '">';
134
135		$t_flag = ( 1 == $t_project );
136
137		if( $g_can_change_workflow ) {
138			$t_flag_name = $p_from_status_id . ':' . $p_to_status_id;
139			$t_set = $t_flag ? 'checked="checked"' : '';
140			$t_value .= '<label><input type="checkbox" class="ace" name="flag[]" value="' . $t_flag_name . '" ' . $t_set . ' /><span class="lbl"></span></label>';
141		} else {
142			$t_value .= $t_flag ? icon_get( 'fa-check', 'fa-lg blue' ) : '&#160;';
143		}
144
145		# Add 'reopened' label
146		if( $p_from_status_id >= $t_resolved_status && $p_to_status_id == $t_reopen_status ) {
147			$t_value .= '<br /><small>(' . $t_reopen_label . ')</small>';
148		}
149	} else {
150		$t_value = '<td>&#160;';
151	}
152
153	$t_value .= '</td>';
154
155	return $t_value;
156}
157
158/**
159 * section header
160 * @param string $p_section_name Section name.
161 * @return void
162 */
163function section_begin( $p_section_name ) {
164	$t_enum_statuses = MantisEnum::getValues( config_get( 'status_enum_string' ) );
165	echo '<div class="space-10"></div>';
166	echo '<div class="widget-box widget-color-blue2">';
167	echo '   <div class="widget-header widget-header-small">';
168	echo '        <h4 class="widget-title lighter uppercase">';
169	echo '            ' . icon_get( 'fa-random', 'ace-icon' );
170	echo $p_section_name;
171	echo '       </h4>';
172	echo '   </div>';
173	echo '   <div class="widget-body">';
174	echo '   <div class="widget-main no-padding">';
175	echo '       <div class="table-responsive">';
176	echo "\t<table  class=\"table table-striped table-bordered table-condensed\">\n";
177	echo "\t\t<thead>\n";
178	echo "\t\t" . '<tr>' . "\n";
179	echo "\t\t\t" . '<th class="bold" rowspan="2">' . lang_get( 'current_status' ) . '</th>'. "\n";
180	echo "\t\t\t" . '<th class="bold" style="text-align:center" colspan="' . ( count( $t_enum_statuses ) + 1 ) . '">'
181		. lang_get( 'next_status' ) . '</th>';
182	echo "\n\t\t" . '</tr>'. "\n";
183	echo "\t\t" . '<tr>' . "\n";
184
185	foreach( $t_enum_statuses as $t_status ) {
186		echo "\t\t\t" . '<th class="bold" style="text-align:center">&#160;'
187			. string_no_break( MantisEnum::getLabel( lang_get( 'status_enum_string' ), $t_status ) )
188			. '&#160;</th>' ."\n";
189	}
190
191	echo "\t\t\t" . '<th class="bold" style="text-align:center">' . lang_get( 'custom_field_default_value' ) . '</th>' . "\n";
192	echo "\t\t" . '</tr>' . "\n";
193	echo "\t\t</thead>\n";
194	echo "\t\t<tbody>\n";
195}
196
197/**
198 * Print row
199 * @param integer $p_from_status From status.
200 * @return void
201 */
202function capability_row( $p_from_status ) {
203	global $g_file_workflow, $g_global_workflow, $g_project_workflow, $g_can_change_workflow;
204	$t_enum_status = MantisEnum::getAssocArrayIndexedByValues( config_get( 'status_enum_string' ) );
205	echo "\t\t" .'<tr><td>' . string_no_break( MantisEnum::getLabel( lang_get( 'status_enum_string' ), $p_from_status ) ) . '</td>' . "\n";
206	foreach ( $t_enum_status as $t_to_status_id => $t_to_status_label ) {
207		echo show_flag( $p_from_status, $t_to_status_id );
208	}
209
210	$t_file = isset( $g_file_workflow['default'][$p_from_status] ) ? $g_file_workflow['default'][$p_from_status] : 0 ;
211	$t_global = isset( $g_global_workflow['default'][$p_from_status] ) ? $g_global_workflow['default'][$p_from_status] : 0 ;
212	$t_project = isset( $g_project_workflow['default'][$p_from_status] ) ? $g_project_workflow['default'][$p_from_status] : 0;
213
214	$t_color = set_color_override( $t_file, $t_global, $t_project );
215	set_overrides( 'status_enum_workflow', $g_can_change_workflow, $t_color );
216
217	echo "\t\t\t" . '<td class="center ' . $t_color . '">';
218	if( $g_can_change_workflow ) {
219		echo '<select name="default_' . $p_from_status . '" class="input-sm">';
220		print_enum_string_option_list( 'status', $t_project );
221		echo '</select>';
222	} else {
223		echo MantisEnum::getLabel( lang_get( 'status_enum_string' ), $t_project );
224	}
225	echo ' </td>' . "\n";
226	echo "\t\t" . '</tr>' . "\n";
227}
228
229/**
230 * section footer
231 * @return void
232 */
233function section_end() {
234	global $g_can_change_workflow;
235	echo '</tbody></table></div>' . "\n";
236	echo '</div></div></div>' . "\n";
237	echo '<div class="space-10"></div>';
238
239	if( $g_can_change_workflow ) {
240		echo lang_get( 'workflow_change_access_label' ) . "&nbsp;\n";
241		echo '<select name="workflow_access">' . "\n";
242		print_enum_string_option_list( 'access_levels', config_get_access( 'status_enum_workflow' ) );
243		echo "\n" . '</select>' . "\n";
244	}
245
246	echo '<div class="space-10"></div>';
247}
248
249/**
250 * threshold section begin
251 * @param string $p_section_name Section name.
252 * @return void
253 */
254function threshold_begin( $p_section_name ) {
255	echo '<div class="space-10"></div>';
256	echo '<div class="widget-box widget-color-blue2">';
257	echo '   <div class="widget-header widget-header-small">';
258	echo '        <h4 class="widget-title lighter uppercase">';
259	echo '            ' . icon_get( 'fa-sliders', 'ace-icon' );
260	echo $p_section_name;
261	echo '       </h4>';
262	echo '   </div>';
263	echo '   <div class="widget-body">';
264	echo '   <div class="widget-main no-padding">';
265	echo '       <div class="table-responsive">';
266	echo '<table class="table table-striped table-bordered table-condensed">';
267	echo '<thead>';
268	echo "\t" . '<tr>';
269	echo "\t\t" . '<th class="bold">' . lang_get( 'threshold' ) . '</th>' . "\n";
270	echo "\t\t" . '<th class="bold" >' . lang_get( 'status_level' ) . '</th>' . "\n";
271	echo "\t\t" . '<th class="bold" >' . lang_get( 'alter_level' ) . '</th></tr>' . "\n";
272	echo "\n";
273	echo '</thead>';
274	echo '<tbody>';
275}
276
277/**
278 * threshold section row
279 * @param string $p_threshold Threshold.
280 * @return void
281 */
282function threshold_row( $p_threshold ) {
283	global $g_access, $g_can_change_flags;
284
285	$t_can_change_threshold = ( $g_access >= config_get_access( $p_threshold ) );
286
287	$t_file = config_get_global( $p_threshold );
288	$t_global = config_get( $p_threshold, null, ALL_USERS, ALL_PROJECTS );
289	$t_project = config_get( $p_threshold );
290	$t_color = set_color_override( $t_file, $t_global, $t_project );
291	set_overrides( $p_threshold, $t_can_change_threshold, $t_color );
292
293	$t_file_access = config_get_global( 'admin_site_threshold' );
294	$t_global_access = config_get_access( $p_threshold, ALL_USERS, ALL_PROJECTS);
295	$t_project_access = config_get_access( $p_threshold );
296	$t_color_access = set_color_override( $t_file_access, $t_global_access, $t_project_access );
297	set_overrides( $p_threshold, $t_can_change_threshold, $t_color_access );
298
299	echo '<tr><td>' . lang_get( 'desc_' . $p_threshold ) . '</td>' . "\n";
300	if( $t_can_change_threshold ) {
301		echo '<td class="' . $t_color . '"><select name="threshold_' . $p_threshold . '" class="input-sm">';
302		print_enum_string_option_list( 'status', $t_project );
303		echo '</select> </td>' . "\n";
304		echo '<td class="' . $t_color_access . '"><select name="access_' . $p_threshold . '" class="input-sm">';
305		print_enum_string_option_list( 'access_levels', config_get_access( $p_threshold ) );
306		echo '</select> </td>' . "\n";
307		$g_can_change_flags = true;
308	} else {
309		echo '<td class="' . $t_color . '">' . MantisEnum::getLabel( lang_get( 'status_enum_string' ), $t_project ) . '&#160;</td>' . "\n";
310		echo '<td>' . MantisEnum::getLabel( lang_get( 'access_levels_enum_string' ), config_get_access( $p_threshold ) ) . '&#160;</td>' . "\n";
311	}
312
313	echo '</tr>' . "\n";
314}
315
316/**
317 * threshold section end
318 * @return void
319 */
320function threshold_end() {
321	echo '</tbody></table></div>' . "\n";
322	echo '</div></div></div>' . "\n";
323	echo '<div class="space-10"></div>';
324}
325
326/**
327 * access begin
328 * @param string $p_section_name Section name.
329 * @return void
330 */
331function access_begin( $p_section_name ) {
332	echo '<div class="space-10"></div>';
333	echo '<div class="widget-box widget-color-blue2">';
334	echo '   <div class="widget-header widget-header-small">';
335	echo '        <h4 class="widget-title lighter uppercase">';
336	echo '            ' . icon_get( 'fa-lock', 'ace-icon' );
337	echo $p_section_name;
338	echo '       </h4>';
339	echo '   </div>';
340	echo '   <div class="widget-body">';
341	echo '   <div class="widget-main no-padding">';
342    echo '        <div class="widget-toolbox padding-8 clearfix">';
343    echo            lang_get( 'access_change' );
344    echo '        </div>';
345    echo '        <div class="table-responsive">';
346    echo '        <table class="table table-striped table-bordered table-condensed">';
347    echo '        <tbody>';
348}
349
350/**
351 * access row
352 * @return void
353 */
354function access_row() {
355	global $g_access, $g_can_change_flags;
356
357	$t_enum_status = MantisEnum::getAssocArrayIndexedByValues( config_get( 'status_enum_string' ) );
358
359	$t_file_new = config_get_global( 'report_bug_threshold' );
360	$t_global_new = config_get( 'report_bug_threshold', null, ALL_USERS, ALL_PROJECTS );
361	$t_report_bug_threshold = config_get( 'report_bug_threshold' );
362
363	$t_file_set = config_get_global( 'set_status_threshold' );
364	$t_global_set = config_get( 'set_status_threshold', null, ALL_USERS, ALL_PROJECTS );
365	$t_project_set = config_get( 'set_status_threshold' );
366
367	$t_submit_status = config_get( 'bug_submit_status' );
368
369	# Print the table rows
370	foreach( $t_enum_status as $t_status => $t_status_label ) {
371		echo "\t\t" . '<tr><td>'
372			. string_no_break( MantisEnum::getLabel( lang_get( 'status_enum_string' ), $t_status ) ) . '</td>' . "\n";
373
374		if( $t_status == $t_submit_status ) {
375			# 'NEW' status
376			$t_threshold = $t_report_bug_threshold;
377
378			$t_can_change = $g_access >= config_get_access( 'report_bug_threshold' );
379			$t_color = set_color_override( $t_file_new, $t_global_new, $t_report_bug_threshold );
380			set_overrides( 'report_bug_threshold', $t_can_change, $t_color );
381		} else {
382			# Other statuses
383
384			# File level: fallback if set_status_threshold is not defined
385			if( isset( $t_file_set[$t_status] ) ) {
386				$t_level_file = $t_file_set[$t_status];
387			} else {
388				$t_level_file = config_get_global( 'update_bug_status_threshold' );
389			}
390
391			$t_level_global  = isset( $t_global_set[$t_status] ) ? $t_global_set[$t_status] : $t_level_file;
392			$t_threshold = isset( $t_project_set[$t_status] ) ? $t_project_set[$t_status] : $t_level_global;
393
394			$t_can_change = ( $g_access >= config_get_access( 'set_status_threshold' ) );
395
396			$t_color = set_color_override( $t_level_file, $t_level_global, $t_threshold );
397			set_overrides( 'set_status_threshold', $t_can_change, $t_color );
398		}
399
400		# If threshold is an array (instead of an integer value), the input is not editable
401		$t_can_edit = !is_array( $t_threshold );
402		$t_min_level = access_threshold_min_level( $t_threshold );
403		if( $t_can_change && $t_can_edit ) {
404			echo '<td class="' . $t_color . '"><select name="access_change_' . $t_status . '" class="input-sm">' . "\n";
405			print_enum_string_option_list( 'access_levels', $t_min_level );
406			echo '</select> </td>' . "\n";
407			$g_can_change_flags = true;
408		} else {
409			echo '<td class="' . $t_color . '">'
410				. MantisEnum::getLabel( lang_get( 'access_levels_enum_string' ), $t_min_level )
411				. '</td>' . "\n";
412		}
413
414		echo '</tr>' . "\n";
415	}
416} # end function access_row
417
418/**
419 * access section end
420 * @return void
421 */
422function access_end() {
423	global $g_access;
424
425	echo '</tbody></table></div>' . "\n";
426	echo '</div></div></div>' . "\n";
427	echo '<div class="space-10"></div>';
428
429	if( $g_access >= config_get_access( 'set_status_threshold' ) ) {
430		echo lang_get( 'access_change_access_label' ) . "&nbsp;\n";
431		echo '<select name="status_access">' . "\n\t\t";
432		print_enum_string_option_list( 'access_levels', config_get_access( 'set_status_threshold' ) );
433		echo "\n" . '</select>' . "\n";
434	}
435
436	echo '<div class="space-10"></div>';
437}
438
439echo '<div class="space-10"></div>';
440
441# count arcs in and out of each status
442$t_enum_status = config_get( 'status_enum_string' );
443$t_status_arr  = MantisEnum::getAssocArrayIndexedByValues( $t_enum_status );
444
445$t_extra_enum_status = '0:non-existent,' . $t_enum_status;
446$t_lang_enum_status = '0:' . lang_get( 'non_existent' ) . ',' . lang_get( 'status_enum_string' );
447$t_all_status = explode( ',', $t_extra_enum_status );
448
449# gather all versions of the workflow
450$g_file_workflow = workflow_parse( config_get_global( 'status_enum_workflow' ) );
451$g_global_workflow = workflow_parse( config_get( 'status_enum_workflow', null, ALL_USERS, ALL_PROJECTS ) );
452$g_project_workflow = workflow_parse( config_get( 'status_enum_workflow', null, ALL_USERS, $t_project ) );
453
454# validate the project workflow
455$t_validation_result = '';
456foreach( $t_status_arr as $t_status => $t_label ) {
457	if( isset( $g_project_workflow['exit'][$t_status][$t_status] ) ) {
458		$t_validation_result .= '<tr><td>'
459						. MantisEnum::getLabel( $t_lang_enum_status, $t_status )
460						. '</td><td class="alert alert-warning">' . lang_get( 'superfluous' ) . '</td></tr>';
461	}
462}
463
464# check for entry == 0 without exit == 0, unreachable state
465foreach( $t_status_arr as $t_status => $t_status_label ) {
466	if( ( 0 == count( $g_project_workflow['entry'][$t_status] ) ) && ( 0 < count( $g_project_workflow['exit'][$t_status] ) ) ) {
467		$t_validation_result .= '<tr><td>'
468						. MantisEnum::getLabel( $t_lang_enum_status, $t_status )
469						. '</td><td class="alert alert-danger">' . lang_get( 'unreachable' ) . '</td></tr>';
470	}
471}
472
473# check for exit == 0 without entry == 0, unleaveable state
474foreach( $t_status_arr as $t_status => $t_status_label ) {
475	if( ( 0 == count( $g_project_workflow['exit'][$t_status] ) ) && ( 0 < count( $g_project_workflow['entry'][$t_status] ) ) ) {
476		$t_validation_result .= '<tr><td>'
477						. MantisEnum::getLabel( $t_lang_enum_status, $t_status )
478						. '</td><td class="alert alert-danger">' . lang_get( 'no_exit' ) . '</td></tr>';
479	}
480}
481
482# check for exit == 0 and entry == 0, isolated state
483foreach ( $t_status_arr as $t_status => $t_status_label ) {
484	if( ( 0 == count( $g_project_workflow['exit'][$t_status] ) ) && ( 0 == count( $g_project_workflow['entry'][$t_status] ) ) ) {
485		$t_validation_result .= '<tr><td>'
486						. MantisEnum::getLabel( $t_lang_enum_status, $t_status )
487						. '</td><td class="alert alert-danger">' . lang_get( 'unreachable' ) . '<br />' . lang_get( 'no_exit' ) . '</td></tr>';
488	}
489}
490
491echo '<form id="workflow_config_action" method="post" action="manage_config_workflow_set.php">' . "\n";
492echo '<fieldset>';
493echo form_security_field( 'manage_config_workflow_set' );
494echo '</fieldset>';
495
496if( ALL_PROJECTS == $t_project ) {
497	$t_project_title = lang_get( 'config_all_projects' );
498} else {
499	$t_project_title = sprintf( lang_get( 'config_project' ), string_display_line( project_get_name( $t_project ) ) );
500}
501
502echo '<div class="col-md-12 col-xs-12">' . "\n";
503echo '<div class="well">' . "\n";
504echo '<p class="bold">' . icon_get( 'fa-info-circle' ) . " $t_project_title</p>\n";
505echo '<p>' . lang_get( 'colour_coding' ) . '<br />';
506if( ALL_PROJECTS <> $t_project ) {
507	echo '<span class="' . COLOR_PROJECT . '">' . lang_get( 'colour_project' ) .'</span><br />';
508}
509echo '<span class="' . COLOR_GLOBAL . '">' . lang_get( 'colour_global' ) . '</span></p>';
510echo '</div>' . "\n";
511
512# show the settings used to derive the table
513threshold_begin( lang_get( 'workflow_thresholds' ) );
514if( !is_array( config_get( 'bug_submit_status' ) ) ) {
515	threshold_row( 'bug_submit_status' );
516}
517threshold_row( 'bug_resolved_status_threshold' );
518threshold_row( 'bug_reopen_status' );
519threshold_end();
520
521if( '' <> $t_validation_result ) {
522	echo '<div class="widget-box widget-color-blue2">';
523	echo '<div class="widget-header widget-header-small">';
524	echo '	<h4 class="widget-title lighter">';
525	echo '		' . icon_get( 'fa-hand-o-right', 'ace-icon' );
526	echo lang_get( 'validation' );
527	echo '	</h4>';
528	echo '</div>';
529	echo '<div class="widget-body">';
530	echo '	<div class="widget-main no-padding">';
531	echo '<div class="table-responsive">';
532	echo '<table class="table table-bordered table-condensed table-striped">';
533	echo '	<tr><td class="bold">' . lang_get( 'status' ) . '</td>';
534	echo '	<td class="bold" >' . lang_get( 'comment' ) . '</td></tr>';
535	echo $t_validation_result;
536	echo '</table></div></div></div></div>';
537}
538
539# Initialization for 'reopened' label handling
540$t_resolved_status = config_get( 'bug_resolved_status_threshold' );
541$t_reopen_status = config_get( 'bug_reopen_status' );
542$t_reopen_label = MantisEnum::getLabel( lang_get( 'resolution_enum_string' ), config_get( 'bug_reopen_resolution' ) );
543
544# display the graph as a matrix
545section_begin( lang_get( 'workflow' ) );
546foreach ( $t_status_arr as $t_from_status => $t_from_label ) {
547	capability_row( $t_from_status );
548}
549section_end();
550
551# display the access levels required to move an issue
552echo "\n\n";
553access_begin( lang_get( 'access_levels' ) );
554access_row();
555access_end();
556echo '</div>';
557
558if( $g_can_change_flags ) {
559	echo '<div class="col-md-12">';
560	echo '<button class="btn btn-primary btn-white btn-round">'
561		. lang_get( 'change_configuration' )
562		. "</button>\n";
563
564	# Deported submit button for separate form defined below
565	# included here to simplify page layout
566	if( 0 < count( $g_overrides ) ) {
567		echo '<button form="mail_config_action" class="btn btn-primary btn-white btn-round">'
568			. lang_get( ALL_PROJECTS == $t_project ? 'revert_to_system' : 'revert_to_all_project' )
569			. "</button>\n";
570	}
571	echo '</div>';
572}
573echo '</form>' . "\n";
574
575# Secondary form to revert config - submit button is defined above
576if( $g_can_change_flags && 0 < count( $g_overrides ) ) {
577?>
578<form id="mail_config_action" method="post" action="manage_config_revert.php">
579	<fieldset>
580		<?php echo form_security_field( 'manage_config_revert' ); ?>
581		<input name="revert" type="hidden" value="<?php echo implode( ',', $g_overrides ) ?>" />
582		<input name="project" type="hidden" value="<?php echo $t_project ?>" />
583		<input name="return" type="hidden" value="<?php echo string_attribute( form_action_self() ) ?>" />
584	</fieldset>
585</form>
586
587<?php
588}
589
590layout_page_end();
591