Docker image / push (push) Canceled after 0s
包含:登录失败锁定、90天密码有效期、30分钟会话超时、 强制改密、登录审计日志、屏幕水印、企业背景图、 备案信息固定底部、favicon、登录页JS修复等全部改动
372 lines
12 KiB
PHP
372 lines
12 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
namespace MRBS;
|
|
|
|
use MRBS\Form\ElementInputSubmit;
|
|
use MRBS\Form\Form;
|
|
|
|
require "defaultincludes.inc";
|
|
|
|
function display_buttons(array $row, bool $is_series) : void
|
|
{
|
|
global $reminders_enabled, $reminder_interval;
|
|
|
|
$last_reminded = (empty($row['reminded'])) ? $row['last_updated'] : $row['reminded'];
|
|
$returl = multisite(this_page());
|
|
|
|
$target_id = ($is_series) ? $row['repeat_id'] : $row['id'];
|
|
|
|
// When we're going to view_entry.php we need to pass the id and series in a
|
|
// query string rather than as hidden inputs. That's because some pages called
|
|
// by view_entry use $_SERVER['HTTP_REFERER'] to form a return URL, and view_entry
|
|
// needs to have a valid id.
|
|
$query_string = "id=$target_id";
|
|
$query_string .= ($is_series) ? "&series=1" : "";
|
|
|
|
if (is_book_admin($row['room_id']))
|
|
{
|
|
// approve
|
|
$form = new Form(Form::METHOD_POST);
|
|
|
|
$attributes = array('action' => multisite('approve_entry_handler.php'));
|
|
$form->setAttributes($attributes);
|
|
|
|
$hidden_inputs = array('action' => 'approve',
|
|
'id' => $target_id,
|
|
'series' => ($is_series) ? 1 : 0,
|
|
'returl' => $returl);
|
|
$form->addHiddenInputs($hidden_inputs);
|
|
|
|
$element = new ElementInputSubmit();
|
|
$element->setAttribute('value', get_vocab('approve'));
|
|
$form->addElement($element);
|
|
|
|
$form->render();
|
|
|
|
// reject
|
|
$form = new Form(Form::METHOD_POST);
|
|
|
|
$attributes = array('action' => multisite("view_entry.php?$query_string"));
|
|
$form->setAttributes($attributes);
|
|
|
|
$hidden_inputs = array('action' => 'reject',
|
|
'returl' => $returl);
|
|
$form->addHiddenInputs($hidden_inputs);
|
|
|
|
$element = new ElementInputSubmit();
|
|
$element->setAttribute('value', get_vocab('reject'));
|
|
$form->addElement($element);
|
|
|
|
$form->render();
|
|
|
|
// more info
|
|
$info_time = ($is_series) ? $row['repeat_info_time'] : $row['entry_info_time'];
|
|
$info_user = ($is_series) ? $row['repeat_info_user'] : $row['entry_info_user'];
|
|
if (empty($info_time))
|
|
{
|
|
$info_title = get_vocab("no_request_yet");
|
|
}
|
|
else
|
|
{
|
|
$info_title = get_vocab("last_request") . ' ' . time_date_string($info_time);
|
|
if (!empty($info_user))
|
|
{
|
|
$info_title .= " " . get_vocab("by") . " $info_user";
|
|
}
|
|
}
|
|
|
|
$form = new Form(Form::METHOD_POST);
|
|
|
|
$attributes = array('action' => multisite("view_entry.php?$query_string"));
|
|
$form->setAttributes($attributes);
|
|
|
|
$hidden_inputs = array('action' => 'more_info',
|
|
'returl' => $returl);
|
|
$form->addHiddenInputs($hidden_inputs);
|
|
|
|
$element = new ElementInputSubmit();
|
|
$element->setAttributes(array('value' => get_vocab('more_info'),
|
|
'title' => $info_title));
|
|
$form->addElement($element);
|
|
|
|
$form->render();
|
|
}
|
|
else
|
|
{
|
|
// get the area settings for this room
|
|
get_area_settings(get_area($row['room_id']));
|
|
// if enough time has passed since the last reminder
|
|
// output a "Remind Admin" button, otherwise nothing
|
|
if ($reminders_enabled &&
|
|
(working_time_diff(time(), $last_reminded) >= $reminder_interval))
|
|
{
|
|
$form = new Form(Form::METHOD_POST);
|
|
|
|
$attributes = array('action' => multisite('approve_entry_handler.php'));
|
|
$form->setAttributes($attributes);
|
|
|
|
$hidden_inputs = array('action' => 'remind',
|
|
'id' => $row['id'],
|
|
'returl' => $returl);
|
|
$form->addHiddenInputs($hidden_inputs);
|
|
|
|
$element = new ElementInputSubmit();
|
|
$element->setAttribute('value', get_vocab('remind_admin'));
|
|
$form->addElement($element);
|
|
|
|
$form->render();
|
|
}
|
|
else
|
|
{
|
|
echo " ";
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
function display_table_head() : void
|
|
{
|
|
echo "<thead>\n";
|
|
echo "<tr>\n";
|
|
// We give some columns a type data value so that the JavaScript knows how to sort them
|
|
echo "<th class=\"control\"> </th>\n";
|
|
echo "<th class=\"header_name\">" . get_vocab("entry") . "</th>\n";
|
|
echo "<th class=\"header_create\">" . get_vocab("createdby") . "</th>\n";
|
|
echo "<th class=\"header_area\">" . get_vocab("area") . "</th>\n";
|
|
echo "<th class=\"header_room\">" . get_vocab("room") . "</th>\n";
|
|
echo "<th class=\"header_start_time\"><span class=\"normal\" data-type=\"title-numeric\">" . get_vocab("start_date") . "</span></th>\n";
|
|
echo "<th class=\"header_duration\"><span class=\"normal\" data-type=\"title-numeric\">" . get_vocab("duration") . "</span></th>\n";
|
|
echo "<th class=\"header_end_time\"><span class=\"normal\" data-type=\"title-numeric\">" . get_vocab("end_date") . "</span></th>\n";
|
|
echo "<th class=\"header_action\">" . get_vocab("action") . "</th>\n";
|
|
echo "</tr>\n";
|
|
echo "</thead>\n";
|
|
}
|
|
|
|
// display the table head for a subtable
|
|
function display_subtable_head(array $row) : void
|
|
{
|
|
echo "<thead>\n";
|
|
echo "<tr>\n";
|
|
// We give some columns a type data value so that the JavaScript knows how to sort them
|
|
echo "<th class=\"control\"> </th>\n";
|
|
// reservation name, with a link to the view_entry page
|
|
echo '<th><a href="' . escape_html(multisite('view_entry.php?id=' . $row['repeat_id'] . '&series=1')) . '">' .
|
|
escape_html($row['name']) ."</a></th>\n";
|
|
|
|
// create_by, area and room names
|
|
echo "<th>" . escape_html($row['create_by']) . "</th>\n";
|
|
echo "<th>" . escape_html($row['area_name']) . "</th>\n";
|
|
echo "<th>" . escape_html($row['room_name']) . "</th>\n";
|
|
|
|
echo "<th><span class=\"normal\" data-type=\"title-numeric\">" . get_vocab("series") . "</span></th>\n";
|
|
echo "<th> </th>\n";
|
|
echo "<th> </th>\n";
|
|
|
|
echo "<th> </th>\n";
|
|
echo "</tr>\n";
|
|
echo "</thead>\n";
|
|
}
|
|
|
|
|
|
// display the title row for a series
|
|
function display_series_title_row(array $row) : void
|
|
{
|
|
echo "<tr id=\"row_" . $row['repeat_id'] . "\">\n";
|
|
echo "<td class=\"control\"> </td>\n";
|
|
// reservation name, with a link to the view_entry page
|
|
echo '<td><a href="' . escape_html(multisite('view_entry.php?id=' . $row['repeat_id'] . '&series=1')) . '">' .
|
|
escape_html($row['name']) ."</a></td>\n";
|
|
|
|
// create_by, area and room names
|
|
echo "<td>" . escape_html(auth()->getDisplayName($row['create_by'])) . "</td>\n";
|
|
echo "<td>" . escape_html($row['area_name']) . "</td>\n";
|
|
echo "<td>" . escape_html($row['room_name']) . "</td>\n";
|
|
|
|
echo "<td>";
|
|
// <span> for sorting
|
|
echo "<span title=\"" . $row['start_time'] . "\"></span>";
|
|
echo get_vocab("series");
|
|
echo "</td>\n";
|
|
|
|
echo "<th><span title=\"0\"></span> </th>\n";
|
|
echo "<th><span title=\"0\"></span> </th>\n";
|
|
|
|
echo "<td>\n";
|
|
display_buttons($row, true);
|
|
echo "</td>\n";
|
|
echo "</tr>\n";
|
|
}
|
|
|
|
// display an entry in a row
|
|
function display_entry_row(array $row) : void
|
|
{
|
|
global $view;
|
|
|
|
echo "<tr>\n";
|
|
echo "<td> </td>\n";
|
|
|
|
// reservation name, with a link to the view_entry page
|
|
echo "<td>";
|
|
echo '<a href="' . escape_html(multisite('view_entry.php?id=' . $row['id'])) . '"' .
|
|
' title="' . escape_html($row['description']) . '">' .
|
|
escape_html($row['name']) ."</a></td>\n";
|
|
|
|
// create_by, area and room names
|
|
echo "<td>" . escape_html(auth()->getDisplayName($row['create_by'])) . "</td>\n";
|
|
echo "<td>" . escape_html($row['area_name']) . "</td>\n";
|
|
echo "<td>" . escape_html($row['room_name']) . "</td>\n";
|
|
|
|
// start date, with a link to the calendar view
|
|
$link = getdate($row['start_time']);
|
|
echo "<td>";
|
|
// <span> for sorting
|
|
echo "<span title=\"" . $row['start_time'] . "\"></span>";
|
|
|
|
$vars = array('view' => $view,
|
|
'year' => $link['year'],
|
|
'month' => $link['mon'],
|
|
'day' => $link['mday'],
|
|
'area' => $row['area_id'],
|
|
'room' => $row['room_id']);
|
|
|
|
$query = http_build_query($vars, '', '&');
|
|
|
|
echo '<a href="' . escape_html(multisite("index.php?$query")) . '">';
|
|
$link_str = date_string(!empty($row['enable_periods']), $row['start_time'], $row['area_id']);
|
|
echo escape_html($link_str) . "</a></td>";
|
|
|
|
$duration = get_duration($row['start_time'], $row['end_time'], !empty($row['enable_periods']), $row['area_id'], false);
|
|
$duration_seconds = $row['end_time'] - $row['start_time'] - cross_dst($row['start_time'], $row['end_time']);
|
|
echo "<td><span title=\"" . $duration_seconds . "\"></span>" . escape_html($duration['duration'] . " " . get_vocab($duration['dur_units'])) . "</td>\n";
|
|
|
|
// End date
|
|
$end_date_str = date_string(!empty($row['enable_periods']), $row['end_time'], $row['area_id'], true);
|
|
echo "<td><span title=\"" . $row['end_time'] . "\"></span>" . escape_html($end_date_str) . "</td>\n";
|
|
|
|
// action buttons
|
|
echo "<td>\n";
|
|
display_buttons($row, false);
|
|
echo "</td>\n";
|
|
echo "</tr>\n";
|
|
}
|
|
|
|
|
|
// Check the user is authorised for this page
|
|
checkAuthorised(this_page());
|
|
|
|
$mrbs_user = session()->getCurrentUser();
|
|
$mrbs_username = (isset($mrbs_user)) ? $mrbs_user->username : null;
|
|
|
|
$context = array(
|
|
'view' => $view,
|
|
'view_all' => $view_all,
|
|
'year' => $year,
|
|
'month' => $month,
|
|
'day' => $day,
|
|
'area' => $area,
|
|
'room' => isset($room) ? $room : null
|
|
);
|
|
|
|
print_header($context);
|
|
|
|
echo "<h1>" . get_vocab("pending") . "</h1>\n";
|
|
|
|
// Get a list of all bookings awaiting approval
|
|
// We are only interested in areas where approval is required
|
|
|
|
$sql_approval_enabled = some_area_predicate('approval_enabled');
|
|
|
|
$sql = "SELECT E.id, E.name, E.description, E.room_id, E.start_time, E.end_time, E.create_by, " .
|
|
db()->syntax_timestamp_to_unix("E.timestamp") . " AS last_updated,
|
|
E.reminded, E.repeat_id,
|
|
M.room_name, M.area_id, A.area_name, A.enable_periods,
|
|
E.info_time AS entry_info_time, E.info_user AS entry_info_user,
|
|
T.info_time AS repeat_info_time, T.info_user AS repeat_info_user
|
|
FROM " . _tbl('room') . " AS M, " . _tbl('area') . " AS A, " . _tbl('entry') . " AS E
|
|
LEFT JOIN " . _tbl('repeat') . " AS T ON E.repeat_id=T.id
|
|
WHERE E.room_id = M.id
|
|
AND M.area_id = A.id
|
|
AND M.disabled = 0
|
|
AND A.disabled = 0
|
|
AND $sql_approval_enabled
|
|
AND (E.status&" . STATUS_AWAITING_APPROVAL . " != 0)";
|
|
|
|
// We want entries for a series to appear together so that we can display
|
|
// them as a separate table below the main entry for the series.
|
|
$sql .= " ORDER BY repeat_id, start_time";
|
|
|
|
$res = db()->query($sql);
|
|
|
|
$rows = array();
|
|
|
|
while (false !== ($row = $res->next_row_keyed()))
|
|
{
|
|
row_cast_columns($row, 'entry');
|
|
// Turn these columns into ints (some MySQL drivers will return a string,
|
|
// and they won't have been caught by row_cast_columns() as they are derived results).
|
|
$row['last_updated'] = intval($row['last_updated']);
|
|
$row['entry_info_time'] = intval($row['entry_info_time']);
|
|
$row['repeat_info_time'] = intval($row['repeat_info_time']);
|
|
// And this comes from the area table
|
|
$row['area_id'] = intval($row['area_id']);
|
|
if ((compare_usernames($row['create_by'], $mrbs_username) === 0) || is_book_admin($row['room_id']))
|
|
{
|
|
$rows[] = $row;
|
|
}
|
|
}
|
|
|
|
if (count($rows) == 0)
|
|
{
|
|
echo "<p>" .get_vocab("none_outstanding") . "</p>\n";
|
|
}
|
|
else // display them in a table
|
|
{
|
|
echo "<div id=\"pending_list\" class=\"datatable_container\">\n";
|
|
echo "<table id=\"pending_table\" class=\"admin_table display\">\n";
|
|
display_table_head();
|
|
|
|
echo "<tbody>\n";
|
|
$last_repeat_id = null;
|
|
$is_series = false;
|
|
foreach ($rows as $row)
|
|
{
|
|
if ($row['repeat_id'] != $last_repeat_id)
|
|
// there's some kind of change
|
|
{
|
|
$last_repeat_id = $row['repeat_id'];
|
|
if ($is_series)
|
|
{
|
|
// end the last series table if there was one
|
|
$is_series = false;
|
|
echo "</tbody></table></div></td></tr>\n";
|
|
}
|
|
|
|
if (!empty($row['repeat_id']))
|
|
{
|
|
// we're starting a new series
|
|
$is_series = true;
|
|
// Put in the title row
|
|
display_series_title_row($row);
|
|
echo "<tr class=\"sub_table\">\n";
|
|
echo "<td class=\"sub_table\" colspan=\"7\">";
|
|
$table_id = "subtable_" . $row['repeat_id'];
|
|
echo "<div class=\"details\">\n";
|
|
echo "<table id=\"$table_id\" class=\"admin_table display sub\">\n";
|
|
display_subtable_head($row);
|
|
echo "<tbody>\n";
|
|
}
|
|
}
|
|
display_entry_row($row);
|
|
}
|
|
if ($is_series)
|
|
{
|
|
// if we were in a series, then close the sub-table
|
|
echo "</tbody></table></div></td></tr>\n";
|
|
}
|
|
echo "</tbody>\n";
|
|
echo "</table>\n";
|
|
echo "</div>\n";
|
|
}
|
|
|
|
print_footer();
|