Make pages work again

This commit is contained in:
Floorb 2022-03-12 13:56:32 -05:00
parent c7fcd033b0
commit ee11e95019
32 changed files with 279 additions and 1361 deletions

View file

@ -139,7 +139,5 @@ $admin_logs = AdminLog::with('user')
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -297,8 +297,5 @@ function getRecentadmin($count = 5) {
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -284,7 +284,5 @@ if (isset($_GET['delete'])) {
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -222,8 +222,6 @@ require_once('common.php');
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" language="javascript" src="js/jquery.dataTables.js"></script>
<script type="text/javascript" language="javascript" class="init">
$(document).ready(function () {
$('#pastesTable').dataTable({
@ -233,6 +231,5 @@ require_once('common.php');
});
});
</script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -291,8 +291,6 @@ if ($last_ip == $ip) {
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" language="javascript" src="js/jquery.dataTables.js"></script>
<script type="text/javascript" language="javascript" class="init">
$(document).ready(function () {
$('#pastesTable').dataTable({

View file

@ -240,7 +240,5 @@ while ($row = mysqli_fetch_array($result)) {
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -1,397 +0,0 @@
<?php
class SSP {
/**
* Create the data output array for the DataTables rows
*
* @param array $columns Column information array
* @param array $data Data from the SQL get
* @return array Formatted data in a row based format
*/
static function data_output($columns, $data) {
$out = array();
for ($i = 0, $ien = count($data); $i < $ien; $i++) {
$row = array();
for ($j = 0, $jen = count($columns); $j < $jen; $j++) {
$column = $columns[$j];
// Is there a formatter?
if (isset($column['formatter'])) {
$row[$column['dt']] = $column['formatter']($data[$i][$column['db']], $data[$i]);
} else {
$row[$column['dt']] = $data[$i][$columns[$j]['db']];
}
}
$out[] = $row;
}
return $out;
}
/**
* Paging
*
* Construct the LIMIT clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL limit clause
*/
static function limit($request, $columns) {
$limit = '';
if (isset($request['start']) && $request['length'] != -1) {
$limit = "LIMIT " . intval($request['start']) . ", " . intval($request['length']);
}
return $limit;
}
/**
* Ordering
*
* Construct the ORDER BY clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL order by clause
*/
static function order($request, $columns) {
$order = '';
if (isset($request['order']) && count($request['order'])) {
$orderBy = array();
$dtColumns = self::pluck($columns, 'dt');
for ($i = 0, $ien = count($request['order']); $i < $ien; $i++) {
// Convert the column index into the column data property
$columnIdx = intval($request['order'][$i]['column']);
$requestColumn = $request['columns'][$columnIdx];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['orderable'] == 'true') {
$dir = $request['order'][$i]['dir'] === 'DESC' ?
'ASC' :
'DESC';
$orderBy[] = '`' . $column['db'] . '` ' . $dir;
}
}
$order = 'ORDER BY ' . implode(', ', $orderBy);
}
return $order;
}
/**
* Searching / Filtering
*
* Construct the WHERE clause for server-side processing SQL query.
*
* NOTE this does not match the built-in DataTables filtering which does it
* word by word on any field. It's possible to do here performance on large
* databases would be very poor
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @param array $bindings Array of values for PDO bindings, used in the
* sql_exec() function
* @return string SQL where clause
*/
static function filter($request, $columns, &$bindings) {
$globalSearch = array();
$columnSearch = array();
$dtColumns = self::pluck($columns, 'dt');
if (isset($request['search']) && $request['search']['value'] != '') {
$str = $request['search']['value'];
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['searchable'] == 'true') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$globalSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
}
// Individual column filtering
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
$str = $requestColumn['search']['value'];
if ($requestColumn['searchable'] == 'true' &&
$str != '') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$columnSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
// Combine the filters into a single string
$where = '';
if (count($globalSearch)) {
$where = '(' . implode(' OR ', $globalSearch) . ')';
}
if (count($columnSearch)) {
$where = $where === '' ?
implode(' AND ', $columnSearch) :
$where . ' AND ' . implode(' AND ', $columnSearch);
}
if ($where !== '') {
$where = 'WHERE ' . $where;
}
return $where;
}
/**
* Perform the SQL queries needed for an server-side processing requested,
* utilising the helper functions of this class, limit(), order() and
* filter() among others. The returned array is ready to be encoded as JSON
* in response to an SSP request, or can be modified if needed before
* sending back to the client.
*
* @param array $request Data sent to server by DataTables
* @param array $sql_details SQL connection details - see sql_connect()
* @param string $table SQL table to query
* @param string $primaryKey Primary key of the table
* @param array $columns Column information array
* @return array Server-side processing response array
*/
static function simple($request, $sql_details, $table, $primaryKey, $columns, $columns2) {
$bindings = array();
$db = self::sql_connect($sql_details);
// Build the SQL query string from the request
$limit = self::limit($request, $columns);
$order = self::order($request, $columns);
$where = self::filter($request, $columns, $bindings);
// Main query to actually get the data
$data = self::Ssql_exec($db, $bindings,
"SELECT SQL_CALC_FOUND_ROWS pastes.id AS id, users.name AS member
FROM `$table`
INNER JOIN users ON users.id = pastes.user_id
$where
$order
$limit"
);
// Data set length after filtering
$resFilterLength = self::sql_exec($db,
"SELECT FOUND_ROWS()"
);
$recordsFiltered = $resFilterLength[0][0];
// Total data set length
$resTotalLength = self::sql_exec($db,
"SELECT COUNT(`{$primaryKey}`)
FROM `$table`"
);
$recordsTotal = $resTotalLength[0][0];
/*
* Output
*/
return array(
"draw" => intval($request['draw']),
"recordsTotal" => intval($recordsTotal),
"recordsFiltered" => intval($recordsFiltered),
"data" => self::data_output($columns2, $data)
);
}
/**
* Connect to the database
*
* @param array $sql_details SQL server connection details array, with the
* properties:
* * host - host name
* * db - database name
* * user - user name
* * pass - user password
* @return resource Database connection handle
*/
static function sql_connect($sql_details) {
try {
$db = @new PDO(
"mysql:host={$sql_details['host']};dbname={$sql_details['db']}",
$sql_details['user'],
$sql_details['pass'],
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
} catch (PDOException $e) {
self::fatal(
"An error occurred while connecting to the database. " .
"The error reported by the server was: " . $e->getMessage()
);
}
return $db;
}
/**
* Execute an SQL query on the database
*
* @param resource $db Database handler
* @param array $bindings Array of PDO binding values from bind() to be
* used for safely escaping strings. Note that this can be given as the
* SQL query string if no bindings are required.
* @param string $sql SQL query to execute.
* @return array Result from the query (all rows)
*/
static function sql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
//echo $sql;
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$result = $stmt->fetchAll();
return $result;
}
static function Ssql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$loop = '0';
while ($arr = $stmt->fetch(PDO::FETCH_ASSOC)) {
$result[$loop]['id'] = $arr['id'];
$result[$loop]['member'] = $arr['member'];
$result[$loop]['ip'] = $arr['ip'];
$vis = Trim($arr['visible']);
if ($vis == '0') {
$result[$loop]['visible'] = "Public";
} elseif ($vis == '1') {
$result[$loop]['visible'] = "Unlisted";
} elseif ($vis == '2') {
$result[$loop]['visible'] = "Private";
}
$myid = $arr['id'];
$result[$loop]['details'] = "<a class='btn btn-default btn-sm' href=pastes.php?details=" . $myid . "> Details </a>";
$result[$loop]['view'] = "<a class='btn btn-success btn-sm' href=../paste.php?id=" . $myid . "> View </a>";
$result[$loop]['delete'] = "<a class='btn btn-danger btn-sm' href=pastes.php?delete=" . $myid . "> Delete </a> <a class='btn btn-link btn-sm' href=ipbans.php?banip=" . $arr['ip'] . "> Ban IP </a>";
$loop = $loop + 1;
}
// Return all
return $result;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Internal methods
*/
/**
* Throw a fatal error.
*
* This writes out an error message in a JSON string which DataTables will
* see and show to the user in the browser.
*
* @param string $msg Message to send to the client
*/
static function fatal($msg) {
echo json_encode(array(
"error" => $msg
));
exit(0);
}
/**
* Create a PDO binding key which can be used for escaping variables safely
* when executing a query with sql_exec()
*
* @param array &$a Array of bindings
* @param * $val Value to bind
* @param int $type PDO field type
* @return string Bound key to be used in the SQL where this parameter
* would be used.
*/
static function bind(&$a, $val, $type) {
$key = ':binding_' . count($a);
$a[] = array(
'key' => $key,
'val' => $val,
'type' => $type
);
return $key;
}
/**
* Pull a particular property from each assoc. array in a numeric array,
* returning and array of the property values from each item.
*
* @param array $a Array to get data from
* @param string $prop Property to read
* @return array Array of property values
*/
static function pluck($a, $prop) {
$out = array();
for ($i = 0, $len = count($a); $i < $len; $i++) {
$out[] = $a[$i][$prop];
}
return $out;
}
}

View file

@ -1,397 +0,0 @@
<?php
class SSP {
/**
* Create the data output array for the DataTables rows
*
* @param array $columns Column information array
* @param array $data Data from the SQL get
* @return array Formatted data in a row based format
*/
static function data_output($columns, $data) {
$out = array();
for ($i = 0, $ien = count($data); $i < $ien; $i++) {
$row = array();
for ($j = 0, $jen = count($columns); $j < $jen; $j++) {
$column = $columns[$j];
// Is there a formatter?
if (isset($column['formatter'])) {
$row[$column['dt']] = $column['formatter']($data[$i][$column['db']], $data[$i]);
} else {
$row[$column['dt']] = $data[$i][$columns[$j]['db']];
}
}
$out[] = $row;
}
return $out;
}
/**
* Paging
*
* Construct the LIMIT clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL limit clause
*/
static function limit($request, $columns) {
$limit = '';
if (isset($request['start']) && $request['length'] != -1) {
$limit = "LIMIT " . intval($request['start']) . ", " . intval($request['length']);
}
return $limit;
}
/**
* Ordering
*
* Construct the ORDER BY clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL order by clause
*/
static function order($request, $columns) {
$order = '';
if (isset($request['order']) && count($request['order'])) {
$orderBy = array();
$dtColumns = self::pluck($columns, 'dt');
for ($i = 0, $ien = count($request['order']); $i < $ien; $i++) {
// Convert the column index into the column data property
$columnIdx = intval($request['order'][$i]['column']);
$requestColumn = $request['columns'][$columnIdx];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['orderable'] == 'true') {
$dir = $request['order'][$i]['dir'] === 'DESC' ?
'ASC' :
'DESC';
$orderBy[] = '`' . $column['db'] . '` ' . $dir;
}
}
$order = 'ORDER BY ' . implode(', ', $orderBy);
}
return $order;
}
/**
* Searching / Filtering
*
* Construct the WHERE clause for server-side processing SQL query.
*
* NOTE this does not match the built-in DataTables filtering which does it
* word by word on any field. It's possible to do here performance on large
* databases would be very poor
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @param array $bindings Array of values for PDO bindings, used in the
* sql_exec() function
* @return string SQL where clause
*/
static function filter($request, $columns, &$bindings) {
$globalSearch = array();
$columnSearch = array();
$dtColumns = self::pluck($columns, 'dt');
if (isset($request['search']) && $request['search']['value'] != '') {
$str = $request['search']['value'];
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['searchable'] == 'true') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$globalSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
}
// Individual column filtering
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
$str = $requestColumn['search']['value'];
if ($requestColumn['searchable'] == 'true' &&
$str != '') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$columnSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
// Combine the filters into a single string
$where = '';
if (count($globalSearch)) {
$where = '(' . implode(' OR ', $globalSearch) . ')';
}
if (count($columnSearch)) {
$where = $where === '' ?
implode(' AND ', $columnSearch) :
$where . ' AND ' . implode(' AND ', $columnSearch);
}
if ($where !== '') {
$where = 'WHERE ' . $where;
}
return $where;
}
/**
* Perform the SQL queries needed for an server-side processing requested,
* utilising the helper functions of this class, limit(), order() and
* filter() among others. The returned array is ready to be encoded as JSON
* in response to an SSP request, or can be modified if needed before
* sending back to the client.
*
* @param array $request Data sent to server by DataTables
* @param array $sql_details SQL connection details - see sql_connect()
* @param string $table SQL table to query
* @param string $primaryKey Primary key of the table
* @param array $columns Column information array
* @return array Server-side processing response array
*/
static function simple($request, $sql_details, $table, $primaryKey, $columns, $columns2) {
$bindings = array();
$db = self::sql_connect($sql_details);
// Build the SQL query string from the request
$limit = self::limit($request, $columns);
$order = self::order($request, $columns);
$where = self::filter($request, $columns, $bindings);
// Main query to actually get the data
$data = self::Ssql_exec($db, $bindings,
"SELECT SQL_CALC_FOUND_ROWS `" . implode("`, `", self::pluck($columns, 'db')) . "`
FROM `$table`
$where
$order
$limit"
);
// Data set length after filtering
$resFilterLength = self::sql_exec($db,
"SELECT FOUND_ROWS()"
);
$recordsFiltered = $resFilterLength[0][0];
// Total data set length
$resTotalLength = self::sql_exec($db,
"SELECT COUNT(`{$primaryKey}`)
FROM `$table`"
);
$recordsTotal = $resTotalLength[0][0];
/*
* Output
*/
return array(
"draw" => intval($request['draw']),
"recordsTotal" => intval($recordsTotal),
"recordsFiltered" => intval($recordsFiltered),
"data" => self::data_output($columns2, $data)
);
}
/**
* Connect to the database
*
* @param array $sql_details SQL server connection details array, with the
* properties:
* * host - host name
* * db - database name
* * user - user name
* * pass - user password
* @return resource Database connection handle
*/
static function sql_connect($sql_details) {
try {
$db = @new PDO(
"mysql:host={$sql_details['host']};dbname={$sql_details['db']}",
$sql_details['user'],
$sql_details['pass'],
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
} catch (PDOException $e) {
self::fatal(
"An error occurred while connecting to the database. " .
"The error reported by the server was: " . $e->getMessage()
);
}
return $db;
}
/**
* Execute an SQL query on the database
*
* @param resource $db Database handler
* @param array $bindings Array of PDO binding values from bind() to be
* used for safely escaping strings. Note that this can be given as the
* SQL query string if no bindings are required.
* @param string $sql SQL query to execute.
* @return array Result from the query (all rows)
*/
static function sql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
//echo $sql;
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$result = $stmt->fetchAll();
return $result;
}
static function Ssql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$loop = '0';
while ($arr = $stmt->fetch(PDO::FETCH_ASSOC)) {
$result[$loop]['id'] = $arr['id'];
$result[$loop]['m_report'] = $arr['m_report'];
$result[$loop]['p_report'] = $arr['p_report'];
$vis = Trim($arr['rep_reason']);
if ($vis == '0') {
$result[$loop]['rep_reason'] = "Public";
} elseif ($vis == '1') {
$result[$loop]['rep_reason'] = "Unlisted";
} elseif ($vis == '2') {
$result[$loop]['rep_reason'] = "Private";
}
$rid = $arr['p_report'];
$result[$loop]['details'] = "<a class='btn btn-default btn-sm' href=pastes.php?details=" . $rid . "> Details </a>";
$result[$loop]['view'] = "<a class='btn btn-success btn-sm' href=../paste.php?id=" . $rid . "> View </a>";
$result[$loop]['delete'] = "<a class='btn btn-danger btn-sm' href=pastes.php?delete=" . $rid . "> Remove </a>";
$result[$loop]['delete'] = "<a class='btn btn-danger btn-sm' href=pastes.php?delete=" . $rid . "> Delete </a>";
$loop = $loop + 1;
}
// Return all
return $result;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Internal methods
*/
/**
* Throw a fatal error.
*
* This writes out an error message in a JSON string which DataTables will
* see and show to the user in the browser.
*
* @param string $msg Message to send to the client
*/
static function fatal($msg) {
echo json_encode(array(
"error" => $msg
));
exit(0);
}
/**
* Create a PDO binding key which can be used for escaping variables safely
* when executing a query with sql_exec()
*
* @param array &$a Array of bindings
* @param * $val Value to bind
* @param int $type PDO field type
* @return string Bound key to be used in the SQL where this parameter
* would be used.
*/
static function bind(&$a, $val, $type) {
$key = ':binding_' . count($a);
$a[] = array(
'key' => $key,
'val' => $val,
'type' => $type
);
return $key;
}
/**
* Pull a particular property from each assoc. array in a numeric array,
* returning and array of the property values from each item.
*
* @param array $a Array to get data from
* @param string $prop Property to read
* @return array Array of property values
*/
static function pluck($a, $prop) {
$out = array();
for ($i = 0, $len = count($a); $i < $len; $i++) {
$out[] = $a[$i][$prop];
}
return $out;
}
}

View file

@ -1,401 +0,0 @@
<?php
class SSP {
/**
* Create the data output array for the DataTables rows
*
* @param array $columns Column information array
* @param array $data Data from the SQL get
* @return array Formatted data in a row based format
*/
static function data_output($columns, $data) {
$out = array();
for ($i = 0, $ien = count($data); $i < $ien; $i++) {
$row = array();
for ($j = 0, $jen = count($columns); $j < $jen; $j++) {
$column = $columns[$j];
// Is there a formatter?
if (isset($column['formatter'])) {
$row[$column['dt']] = $column['formatter']($data[$i][$column['db']], $data[$i]);
} else {
$row[$column['dt']] = $data[$i][$columns[$j]['db']];
}
}
$out[] = $row;
}
return $out;
}
/**
* Paging
*
* Construct the LIMIT clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL limit clause
*/
static function limit($request, $columns) {
$limit = '';
if (isset($request['start']) && $request['length'] != -1) {
$limit = "LIMIT " . intval($request['start']) . ", " . intval($request['length']);
}
return $limit;
}
/**
* Ordering
*
* Construct the ORDER BY clause for server-side processing SQL query
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @return string SQL order by clause
*/
static function order($request, $columns) {
$order = '';
if (isset($request['order']) && count($request['order'])) {
$orderBy = array();
$dtColumns = self::pluck($columns, 'dt');
for ($i = 0, $ien = count($request['order']); $i < $ien; $i++) {
// Convert the column index into the column data property
$columnIdx = intval($request['order'][$i]['column']);
$requestColumn = $request['columns'][$columnIdx];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['orderable'] == 'true') {
$dir = $request['order'][$i]['dir'] === 'asc' ?
'ASC' :
'DESC';
$orderBy[] = '`' . $column['db'] . '` ' . $dir;
}
}
$order = 'ORDER BY ' . implode(', ', $orderBy);
}
return $order;
}
/**
* Searching / Filtering
*
* Construct the WHERE clause for server-side processing SQL query.
*
* NOTE this does not match the built-in DataTables filtering which does it
* word by word on any field. It's possible to do here performance on large
* databases would be very poor
*
* @param array $request Data sent to server by DataTables
* @param array $columns Column information array
* @param array $bindings Array of values for PDO bindings, used in the
* sql_exec() function
* @return string SQL where clause
*/
static function filter($request, $columns, &$bindings) {
$globalSearch = array();
$columnSearch = array();
$dtColumns = self::pluck($columns, 'dt');
if (isset($request['search']) && $request['search']['value'] != '') {
$str = $request['search']['value'];
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
if ($requestColumn['searchable'] == 'true') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$globalSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
}
// Individual column filtering
for ($i = 0, $ien = count($request['columns']); $i < $ien; $i++) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search($requestColumn['data'], $dtColumns);
$column = $columns[$columnIdx];
$str = $requestColumn['search']['value'];
if ($requestColumn['searchable'] == 'true' &&
$str != '') {
$binding = self::bind($bindings, '%' . $str . '%', PDO::PARAM_STR);
$columnSearch[] = "`" . $column['db'] . "` LIKE " . $binding;
}
}
// Combine the filters into a single string
$where = '';
if (count($globalSearch)) {
$where = '(' . implode(' OR ', $globalSearch) . ')';
}
if (count($columnSearch)) {
$where = $where === '' ?
implode(' AND ', $columnSearch) :
$where . ' AND ' . implode(' AND ', $columnSearch);
}
if ($where !== '') {
$where = 'WHERE ' . $where;
}
return $where;
}
/**
* Perform the SQL queries needed for an server-side processing requested,
* utilising the helper functions of this class, limit(), order() and
* filter() among others. The returned array is ready to be encoded as JSON
* in response to an SSP request, or can be modified if needed before
* sending back to the client.
*
* @param array $request Data sent to server by DataTables
* @param array $sql_details SQL connection details - see sql_connect()
* @param string $table SQL table to query
* @param string $primaryKey Primary key of the table
* @param array $columns Column information array
* @return array Server-side processing response array
*/
static function simple($request, $sql_details, $table, $primaryKey, $columns, $columns2) {
$bindings = array();
$db = self::sql_connect($sql_details);
// Build the SQL query string from the request
$limit = self::limit($request, $columns);
$order = self::order($request, $columns);
$where = self::filter($request, $columns, $bindings);
// Main query to actually get the data
$data = self::Ssql_exec($db, $bindings,
"SELECT SQL_CALC_FOUND_ROWS `" . implode("`, `", self::pluck($columns, 'db')) . "`
FROM `$table`
$where
$order
$limit"
);
// Data set length after filtering
$resFilterLength = self::sql_exec($db,
"SELECT FOUND_ROWS()"
);
$recordsFiltered = $resFilterLength[0][0];
// Total data set length
$resTotalLength = self::sql_exec($db,
"SELECT COUNT(`{$primaryKey}`)
FROM `$table`"
);
$recordsTotal = $resTotalLength[0][0];
/*
* Output
*/
return array(
"draw" => intval($request['draw']),
"recordsTotal" => intval($recordsTotal),
"recordsFiltered" => intval($recordsFiltered),
"data" => self::data_output($columns2, $data)
);
}
/**
* Connect to the database
*
* @param array $sql_details SQL server connection details array, with the
* properties:
* * host - host name
* * db - database name
* * user - user name
* * pass - user password
* @return resource Database connection handle
*/
static function sql_connect($sql_details) {
try {
$db = @new PDO(
"mysql:host={$sql_details['host']};dbname={$sql_details['db']}",
$sql_details['user'],
$sql_details['pass'],
array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)
);
} catch (PDOException $e) {
self::fatal(
"An error occurred while connecting to the database. " .
"The error reported by the server was: " . $e->getMessage()
);
}
return $db;
}
/**
* Execute an SQL query on the database
*
* @param resource $db Database handler
* @param array $bindings Array of PDO binding values from bind() to be
* used for safely escaping strings. Note that this can be given as the
* SQL query string if no bindings are required.
* @param string $sql SQL query to execute.
* @return array Result from the query (all rows)
*/
static function sql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
//echo $sql;
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$result = $stmt->fetchAll();
return $result;
}
static function Ssql_exec($db, $bindings, $sql = null) {
// Argument shifting
if ($sql === null) {
$sql = $bindings;
}
$stmt = $db->prepare($sql);
// Bind parameters
if (is_array($bindings)) {
for ($i = 0, $ien = count($bindings); $i < $ien; $i++) {
$binding = $bindings[$i];
$stmt->bindValue($binding['key'], $binding['val'], $binding['type']);
}
}
// Execute
try {
$stmt->execute();
} catch (PDOException $e) {
self::fatal("An SQL error occurred: " . $e->getMessage());
}
$loop = '0';
while ($arr = $stmt->fetch(PDO::FETCH_ASSOC)) {
$result[$loop]['id'] = $arr['id'];
$result[$loop]['username'] = $arr['username'];
$result[$loop]['platform'] = $arr['platform'];
$result[$loop]['date'] = $arr['date'];
$ver = $arr['verified'];
$myid = $arr['id'];
if ($ver == '0') {
$result[$loop]['ban'] = "<span class='bg-red'>User unverified</span>";
} elseif ($ver == '1') {
$result[$loop]['ban'] = "<a class='btn btn-danger btn-sm' href=users.php?ban=" . $myid . "> Ban </a>";
} elseif ($ver == '2') {
$result[$loop]['ban'] = "<a class='btn btn-success btn-sm' href=users.php?unban=" . $myid . "> Unban </a>";
}
$result[$loop]['view'] = "<a class='btn btn-default btn-sm' href=users.php?details=" . $myid . "> Details </a>";
$result[$loop]['delete'] = "<a class='btn btn-danger btn-sm' href=users.php?delete=" . $myid . "> Delete </a>";
$loop = $loop + 1;
}
// Return all
return $result;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Internal methods
*/
/**
* Throw a fatal error.
*
* This writes out an error message in a JSON string which DataTables will
* see and show to the user in the browser.
*
* @param string $msg Message to send to the client
*/
static function fatal($msg) {
echo json_encode(array(
"error" => $msg
));
exit(0);
}
/**
* Create a PDO binding key which can be used for escaping variables safely
* when executing a query with sql_exec()
*
* @param array &$a Array of bindings
* @param * $val Value to bind
* @param int $type PDO field type
* @return string Bound key to be used in the SQL where this parameter
* would be used.
*/
static function bind(&$a, $val, $type) {
$key = ':binding_' . count($a);
$a[] = array(
'key' => $key,
'val' => $val,
'type' => $type
);
return $key;
}
/**
* Pull a particular property from each assoc. array in a numeric array,
* returning and array of the property values from each item.
*
* @param array $a Array to get data from
* @param string $prop Property to read
* @return array Array of property values
*/
static function pluck($a, $prop) {
$out = array();
for ($i = 0, $len = count($a); $i < $len; $i++) {
$out[] = $a[$i][$prop];
}
return $out;
}
}
if ($_SERVER['HTTP_X_REQUESTED_WITH'] != "XMLHttpRequest") {
header("Location: http://ponepaste.org/SVOtaKqJZh4nT9Z");
die();
}

View file

@ -327,7 +327,5 @@ if ($last_ip == $ip) {
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
</body>
</html>

View file

@ -184,8 +184,6 @@ require_once(__DIR__ . '/common.php');
</div>
<!-- End content -->
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" language="javascript" src="js/jquery.dataTables.js"></script>
<script type="text/javascript" language="javascript" class="init">
$(document).ready(function () {
$('#usersTable').dataTable({

View file

@ -10,7 +10,7 @@ $date = date('jS F Y');
// Temp count for untagged pastes
$total_untagged = Paste::doesntHave('tags')->count();
updatePageViews($conn);
updatePageViews();
// Theme
$page_template = 'archive';

8
includes/Models/Page.php Normal file
View file

@ -0,0 +1,8 @@
<?php
namespace PonePaste\Models;
use Illuminate\Database\Eloquent\Model;
class Page extends Model {
protected $table = 'pages';
}

View file

@ -14,7 +14,7 @@ class User extends Model {
}
public function favourites() {
return $this->belongsToMany(Paste::class, 'user_favourites');
return $this->belongsToMany(Paste::class, 'user_favourites')->withPivot('f_time');
}
public function pastes() {

View file

@ -3,7 +3,7 @@
use Illuminate\Database\Eloquent\Builder;
class NonRetardedSSP {
public static function run(DatabaseHandle $conn, array $request, Builder $builder) {
public static function run(array $request, Builder $builder) {
/* Some of these parameters might not be passed; zero is an OK default */
$draw = (int) @$request['draw'];
$start = (int) @$request['start'];

View file

@ -47,6 +47,9 @@ function urlForMember(User $user) : string {
return '/user.php?name=' . urlencode($user->username);
}
/**
* @throws Exception if the names and values aren't the same length
*/
function optionsForSelect(array $displays, array $values, string $currentSelection = null) : string {
$size = count($displays);
@ -69,6 +72,9 @@ function optionsForSelect(array $displays, array $values, string $currentSelecti
return $html;
}
/**
* @throws Exception if the flash level is invalid
*/
function flash(string $level, string $message) {
if (!isset($_SESSION['flashes'])) {
$_SESSION['flashes'] = [
@ -121,7 +127,7 @@ function pp_html_escape(string $unescaped) : string {
}
/* I think there is one row for each day, and in that row, tpage = non-unique, tvisit = unique page views for that day */
function updatePageViews(DatabaseHandle $conn) : void {
function updatePageViews() : void {
global $redis;
$ip = $_SERVER['REMOTE_ADDR'];
@ -130,8 +136,6 @@ function updatePageViews(DatabaseHandle $conn) : void {
$last_page_view = PageView::orderBy('id', 'desc')->limit(1)->first();
if ($last_page_view && $last_page_view->date == $date) {
$last_tpage = intval($last_page_view->tpage) + 1;
if (!$redis->sIsMember('page_view_ips', $ip)) {
$last_page_view->tvisit++;
$redis->sAdd('page_view_ips', $ip);
@ -153,7 +157,6 @@ function updatePageViews(DatabaseHandle $conn) : void {
session_start();
/* Set up the database and Eloquent ORM */
$conn = new DatabaseHandle("mysql:host=$db_host;dbname=$db_schema;charset=utf8mb4", $db_user, $db_pass);
$capsule = new Capsule();
$capsule->addConnection([
@ -168,6 +171,12 @@ $capsule->addConnection([
$capsule->setAsGlobal();
$capsule->bootEloquent();
// Check if IP is banned
$ip = $_SERVER['REMOTE_ADDR'];
if (IPBan::where('ip', $ip)->first()) {
die('You have been banned.');
}
/* Set up Redis */
$redis = new Redis();
$redis->pconnect(PP_REDIS_HOST);
@ -200,11 +209,7 @@ if ($site_permissions) {
$captcha_config = $site_info['captcha'];
$captcha_enabled = (bool) $captcha_config['enabled'];
// Check if IP is banned
$ip = $_SERVER['REMOTE_ADDR'];
if (IPBan::where('ip', $ip)->first()) {
die('You have been banned.');
}
$total_pastes = Paste::count();
$total_page_views = PageView::select('tpage')->orderBy('id', 'desc')->first()->tpage;

View file

@ -226,22 +226,14 @@ function embedView($paste_id, $p_title, $content, $p_code, $title, $baseurl, $la
return $stats;
}
function addToSitemap($paste_id, $priority, $changefreq, $mod_rewrite) {
function addToSitemap(\PonePaste\Models\Paste $paste, $priority, $changefreq) {
$c_date = date('Y-m-d');
$site_data = file_get_contents("sitemap.xml");
$site_data = str_replace("</urlset>", "", $site_data);
// which protocol are we on
$protocol = paste_protocol();
if (PP_MOD_REWRITE) {
$server_name = $protocol . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . "/" . $paste_id;
} else {
$server_name = $protocol . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . "/paste.php?id=" . $paste_id;
}
$c_sitemap =
' <url>
<loc>' . $server_name . '</loc>
<loc>' . urlForPaste($paste) . '</loc>
<priority>' . $priority . '</priority>
<changefreq>' . $changefreq . '</changefreq>
<lastmod>' . $c_date . '</lastmod>

View file

@ -42,4 +42,4 @@ function pp_random_password() : string {
* can reasonably be handled by a user.
*/
return hash('MD5', pp_random_bytes(64));
}
}

View file

@ -35,7 +35,7 @@ function verifyCaptcha() : string|bool {
function calculatePasteExpiry(string $expiry) {
// used to use mktime
if ($expiry === 'self') {
return 'SELF'; // What does this do?
return 'SELF';
}
$valid_expiries = ['10M', '1H', '1D', '1W', '2W', '1M'];
@ -62,11 +62,8 @@ function validatePasteFields() : string|null {
}
// Sitemap
$site_sitemap_rows = $conn->query('SELECT * FROM sitemap_options LIMIT 1');
if ($row = $site_sitemap_rows->fetch()) {
$priority = $row['priority'];
$changefreq = $row['changefreq'];
}
$priority = 0.9;
$changefreq = 'weekly';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
if ($captcha_config['enabled']) {
@ -74,7 +71,7 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
}
}
updatePageViews($conn);
updatePageViews();
// POST Handler
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
@ -164,7 +161,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$paste_id = $new_paste->id;
if ($p_visible == '0') {
addToSitemap($paste_id, $priority, $changefreq, $mod_rewrite);
addToSitemap($paste, $priority, $changefreq);
}
}

View file

@ -1,5 +1,5 @@
import { escape, whenReady } from './dom';
import { DataTable } from './data_tables';
import { DataTable, dumbFilterCallback } from './data_tables';
import { globalSetup } from './main';
whenReady(() => {
@ -39,20 +39,7 @@ whenReady(() => {
<td>${tags}</td>
</tr>`;
},
filterCallback: (datum, query) => {
if (datum.title.indexOf(query) !== -1) {
return true;
}
/* this is inefficient */
for (const tag of datum.tags) {
if (tag.name.toLowerCase() === query.toLowerCase()) {
return true;
}
}
return false;
},
filterCallback: dumbFilterCallback,
preFilter: myParam
});
table.attach();

View file

@ -21,6 +21,10 @@ class SimplePaginator {
const lastPage = Math.floor(totalRecords / perPage); // ish?
const numPagesToShow = 2;
if (lastPage === firstPage) {
return;
}
/* First and last page the main paginator will show */
const firstPageShow = (currentPage - firstPage) < numPagesToShow ? firstPage : ((currentPage - numPagesToShow < 0) ? currentPage : currentPage - numPagesToShow);
const lastPageShow = (firstPageShow + numPagesToShow) > lastPage ? lastPage : (firstPageShow + numPagesToShow + numPagesToShow);
@ -86,6 +90,9 @@ class DataTable {
this.paginator = new SimplePaginator(this.container.querySelector('.paginator'));
this.filterCallback = options.filterCallback;
this.sortField = null;
this.sortDir = true;
this.reverseRowCallback = options.reverseRowCallback;
}
attach() {
@ -102,17 +109,44 @@ class DataTable {
}
}
const header = this.element.querySelector('tr.paginator__sort');
if (header) {
header.addEventListener('click', evt => {
const target = evt.target;
if (!target.dataset.sortField) {
return;
}
if (this.sortField) {
const elem = this.element.querySelector(`th[data-sort-field=${this.sortField}]`)
elem.classList.remove('paginator__sort--down');
elem.classList.remove('paginator__sort--up');
}
this._updateSort(target.dataset.sortField, !this.sortDir);
target.classList.add(this.sortDir ? 'paginator__sort--up' : 'paginator__sort--down');
});
}
this.paginator.attach(this._updatePage.bind(this));
this._loadEntries();
}
/* Load the requested data from the server, and when done, update the DOM. */
_loadEntries() {
new Promise(this.ajaxCallback)
.then(data => {
this.unfilteredData = data.data;
this._updateFilter(this.options.preFilter);
});
if (this.ajaxCallback) {
new Promise(this.ajaxCallback)
.then(data => {
this.unfilteredData = data.data;
this._updateFilter(this.options.preFilter);
});
} else if (this.reverseRowCallback) {
this.unfilteredData = Array.prototype.map.call(this.element.querySelectorAll('tr'), this.reverseRowCallback).filter(row => row);
this._updateFilter(this.options.preFilter);
}
}
/* Update the DOM to reflect the current state of the data we have loaded */
@ -162,8 +196,43 @@ class DataTable {
}
_updateSort(field, direction) {
this.sortField = field;
this.sortDir = direction;
let newEntries = [...this.data].sort((a, b) => {
let sorter = 0;
if (a[field] > b[field]) {
sorter = 1;
} else if (a[field] < b[field]) {
sorter = -1;
}
if (!direction) {
sorter = -sorter;
}
return sorter;
});
this._updatePage(0);
this._updateEntries(newEntries);
}
}
export { DataTable };
const dumbFilterCallback = (datum, query) => {
if (datum.title.indexOf(query) !== -1) {
return true;
}
/* this is inefficient */
for (const tag of datum.tags) {
if (tag.name.toLowerCase() === query.toLowerCase()) {
return true;
}
}
return false;
};
export { DataTable, dumbFilterCallback };

87
js/user_profile.js Normal file
View file

@ -0,0 +1,87 @@
import { escape, whenReady } from './dom';
import { DataTable, dumbFilterCallback } from './data_tables';
import { globalSetup } from './main';
const parsePasteInfo = (elem) => {
if (!elem.dataset.pasteInfo) {
return null;
}
return JSON.parse(elem.dataset.pasteInfo);
};
whenReady(() => {
globalSetup();
const urlParams = new URLSearchParams(window.location.search);
const myParam = urlParams.get('q');
const table = new DataTable(document.getElementById('archive'), {
reverseRowCallback: parsePasteInfo,
rowCallback: (rowData) => {
const tags = rowData.tags.map((tagData) => {
let tagColorClass;
if (tagData.name.indexOf('nsfw') !== -1) {
tagColorClass = 'is-danger';
} else if (tagData.name.indexOf('safe') !== -1) {
tagColorClass = 'is-success';
} else if (tagData.name.indexOf('/') !== -1) {
tagColorClass = 'is-primary';
} else {
tagColorClass = 'is-info';
}
return `<a href="/archive?q=${tagData.slug}">
<span class="tag ${tagColorClass}">${escape(tagData.name)}</span>
</a>`;
}).join('');
return `<tr>
<td><a href="/${rowData.id}">${escape(rowData.title)}</a></td>
<td>${rowData.created_at}</td>
<td>${rowData.visibility}</td>
<td>${rowData.views || 0}</td>
<td>${tags}</td>
</tr>`;
},
filterCallback: dumbFilterCallback,
preFilter: myParam
});
table.attach();
const faveTable = new DataTable(document.getElementById('favs'), {
reverseRowCallback: parsePasteInfo,
rowCallback: (rowData) => {
const tags = rowData.tags.map((tagData) => {
let tagColorClass;
if (tagData.name.indexOf('nsfw') !== -1) {
tagColorClass = 'is-danger';
} else if (tagData.name.indexOf('safe') !== -1) {
tagColorClass = 'is-success';
} else if (tagData.name.indexOf('/') !== -1) {
tagColorClass = 'is-primary';
} else {
tagColorClass = 'is-info';
}
return `<a href="/archive?q=${tagData.slug}">
<span class="tag ${tagColorClass}">${escape(tagData.name)}</span>
</a>`;
}).join('');
const recentUpdate = rowData.recently_updated ?
`<i class='far fa-check-square fa-lg' aria-hidden='true'></i>` :
`<i class='far fa-minus-square fa-lg' aria-hidden='true'></i>`;
// <td><a href="/user/${escape(rowData.author)}">${escape(rowData.author)}</a></td>
return `<tr>
<td><a href="/${rowData.id}">${escape(rowData.title)}</a></td>
<td>${rowData.favourited_at}</td>
<td>${recentUpdate}</td>
<td>${tags}</td>
</tr>`;
},
filterCallback: dumbFilterCallback,
preFilter: myParam
});
faveTable.attach();
});

View file

@ -19,7 +19,7 @@ if ($current_user !== null) {
die();
}
updatePageViews($conn);
updatePageViews();
if (isset($_POST['forgot'])) {
if (!empty($_POST['username']) && !empty($_POST['recovery_code'])) {

View file

@ -3,13 +3,15 @@ define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');
use PonePaste\Helpers\SessionHelper;
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || $current_user === null) {
header('Location: ' . $_SERVER['HTTP_REFERER']);
die();
}
/* Destroy remember token */
\PonePaste\Helpers\SessionHelper::destroySession();
SessionHelper::destroySession();
/* Destroy PHP session */
unset($_SESSION['user_id']);

View file

@ -3,24 +3,19 @@ define('IN_PONEPASTE', 1);
require_once('includes/common.php');
require_once('includes/functions.php');
updatePageViews($conn);
use PonePaste\Models\Page;
updatePageViews();
if (isset($_GET['page'])) {
$page_name = htmlspecialchars(trim($_GET['page']));
$query = $conn->prepare('SELECT page_title, page_content, last_date FROM pages WHERE page_name = ?');
$query->execute([$page_name]);
if ($row = $query->fetch()) {
$page_title = $row['page_title'];
$page_content = $row['page_content'];
$last_date = $row['last_date'];
$stats = "OK";
$p_title = $page_title;
}
$page = Page::select('page_title', 'page_content', 'last_date')
->where('page_name', $_GET['page'])
->first();
$page_title = $page->page_title;
} else {
$page_title = 'Page not found';
}
// Theme
$page_template = 'pages';
require_once('theme/' . $default_theme . '/common.php');

View file

@ -39,7 +39,7 @@ function getUserRecommended(User $user) {
$paste_id = intval(trim($_REQUEST['id']));
updatePageViews($conn);
updatePageViews();
// This is used in the theme files.
$totalpastes = Paste::count();

View file

@ -37,7 +37,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
}
}
updatePageViews($conn);
updatePageViews();
$total_user_pastes = Paste::where('user_id', $current_user->id)->count();

View file

@ -23,5 +23,6 @@ const output = (name) => {
export default [
output('generic'),
output('archive')
output('archive'),
output('user_profile')
];

View file

@ -7,6 +7,24 @@
pointer-events: none;
color: gray;
}
.paginator__sort > th {
cursor: pointer;
}
.paginator__sort--down, .paginator__sort--up {
background-color: lightblue;
}
.paginator__sort--down:after {
padding-left: 0.25rem;
content: '▼';
}
.paginator__sort--up:after {
padding-left: 0.25rem;
content: '▲';
}
</style>
<main class="bd-main">
@ -31,10 +49,10 @@
</div>
<table id="archive" class="table is-fullwidth is-hoverable">
<thead>
<tr>
<th>Title</th>
<th>Author</th>
<th>Tags</th>
<tr class="paginator__sort">
<th data-sort-field="title">Title</th>
<th data-sort-field="author">Author</th>
<th data-sort-field="tags">Tags</th>
</tr>
</thead>
<tbody>

View file

@ -3,14 +3,13 @@
<div class="bd-main-container container">
<div class="bd-duo">
<div class="bd-lead">
<h1 class="title is-4"><?php echo $page_title; ?><h1>
<?php
if (isset($stats)) {
echo $page_content;
} else {
echo '<p class="help is-danger subtitle is-6">Not Found</p>';
}
?>
<?php if (isset($page)): ?>
<h1 class="title is-4"><?= pp_html_escape($page->page_title); ?><h1>
<?= $page->page_content; ?>
<?php else: ?>
<h1 class="title is-4">Page not found.</h1>
<p class="help is-danger subtitle is-6">A page with that name doesn't seem to exist.</p>
<?php endif; ?>
</div>
</div>
</div>

View file

@ -1,46 +1,3 @@
<script>
$(document).ready(function () {
$("#archive").dataTable({
rowReorder: {selector: 'td:nth-child(2)'},
responsive: true,
pageLength: 50,
order: [[ 1, "desc" ]],
autoWidth: false,
initComplete: function () {
var search = new URLSearchParams(window.location.search);
var query = search.get('q');
if (query) {
$("#archive_filter input")
.val(query)
.trigger("input");
}
}
})
});
</script>
<?php if ($current_user) { ?>
<script>
$(document).ready(function () {
$("#favs").dataTable({
rowReorder: { selector: 'td:nth-child(2)'},
responsive: true,
order: [[ 2, "desc" ]],
pageLength: 50,
autoWidth: false,
initComplete: function () {
var search = new URLSearchParams(window.location.search);
var query = search.get('q');
if (query) {
$("#archive_filter input")
.val(query)
.trigger("input");
}
}
})
});
</script>
<?php } ?>
<?php
$public_paste_badges = [
50 => '[ProbablyAutistic] Have more than Fifty pastes',
@ -87,11 +44,11 @@
<h2 class="title is-5">Badges</h2>
<?php
if (strtotime($profile_join_date) <= 1604188800) {
echo '<img src = "/img/badges/adopter.png" title="[EarlyAdopter] Joined during the first wave " style="margin:5px">';
echo '<img src="/img/badges/adopter.png" title="[EarlyAdopter] Joined during the first wave " style="margin:5px">';
} elseif (strtotime($profile_join_date) <= 1608422400) {
echo '<img src = "/img/badges/pioneer.png" title="[EarlyPioneer] Joined during the Second wave " style="margin:5px">';
echo '<img src="/img/badges/pioneer.png" title="[EarlyPioneer] Joined during the Second wave " style="margin:5px">';
} elseif (strtotime($profile_join_date) <= 1609459200) {
echo '<img src = "/img/badges/strag.png" title="[EarlyStraggeler] Joined after the Second wave " style="margin:5px">';
echo '<img src="/img/badges/strag.png" title="[EarlyStraggeler] Joined after the Second wave " style="margin:5px">';
}
if (!str_contains($profile_badge, '0')) {
echo $profile_badge;
@ -143,15 +100,15 @@
<table id="archive" class="table is-fullwidth is-hoverable">
<thead>
<tr>
<td class="td-right">Title</td>
<td class="td-center">Paste Time</td>
<th class="td-right">Title</th>
<th class="td-center">Paste Time</th>
<?php if ($is_current_user) {
echo "<td class='td-center'>Visibility</td>";
echo "<th class='td-center'>Visibility</th>";
} ?>
<td class="td-center">Views</td>
<td class="td-center">Tags</td>
<th class="td-center">Views</th>
<th class="td-center">Tags</th>
<?php if ($is_current_user) {
echo "<td class='td-center'>Delete</td>";
echo "<th class='td-center'>Delete</th>";
} ?>
</tr>
</thead>
@ -165,9 +122,13 @@
1 => 'Unlisted',
2 => 'Private'
};
$pasteJson = array_merge(
$paste->only('id', 'title', 'tags', 'views', 'created_at'),
['visibility' => $p_visible]
);
?>
<?php if ($is_current_user || $row['visible'] == Paste::VISIBILITY_PUBLIC): ?>
<tr>
<tr data-paste-info="<?= pp_html_escape(json_encode($pasteJson)); ?>">
<td><a href="<?= urlForPaste($paste) ?>" title="<?= $escaped_title ?>"><?= $escaped_title ?></a></td>
<td data-sort="<?= $p_date->format('U') ?>" class="td-center"><?= $p_date->format('d F Y') ?></td>
<td class="td-center"><?= $p_visible; ?></td>
@ -180,29 +141,30 @@
</tbody>
<tfoot>
<tr>
<td class="td-center">Title</td>
<td class="td-center">Paste Time</td>
<th class="td-center">Title</th>
<th class="td-center">Paste Time</th>
<?php if ($is_current_user) {
echo "<td class='td-center'>Visibility</td>";
} ?>
<td class="td-center">Views</td>
<td class="td-center">Tags</td>
<th class="td-center">Views</th>
<th class="td-center">Tags</th>
<?php if ($is_current_user) {
echo "<td class='td-center'>Delete</td>";
} ?>
</tr>
</tfoot>
</table>
<div class="paginator"></div>
</div>
<?php if ($is_current_user) { ?>
<div class="tab-content" id="second-tab">
<table id="favs" class="table is-fullwidth is-hoverable">
<thead>
<tr>
<td class="td-right">Title</td>
<td class="td-center">Date Favourited</td>
<td class="td-center">Status</td>
<td class="td-center">Tags</td>
<th class="td-right">Title</th>
<th class="td-center">Date Favourited</th>
<th class="td-center">Status</th>
<th class="td-center">Tags</th>
</tr>
</thead>
<tbody>
@ -212,11 +174,15 @@
$f_date = new DateTime($paste->pivot->f_time);
$update_date = new DateTime($paste->updated_at);
$delta = $update_date->diff(new DateTime(), true);
$pasteJson = array_merge(
$paste->only('id', 'title', 'tags', 'views', 'created_at'),
['recently_updated' => ($delta->days <= 2), 'favourited_at' => $f_date->format('d F Y')]
);
?>
<?php if ($is_current_user || $row['visible'] == Paste::VISIBILITY_PUBLIC): ?>
<tr>
<tr data-paste-info="<?= pp_html_escape(json_encode($pasteJson)); ?>">
<td><a href="<?= urlForPaste($paste) ?>" title="<?= $escaped_title ?>"><?= $escaped_title ?></a></td>
<td data-sort="<?= $p_date->format('U') ?>" class="td-center"><?= $p_date->format('d F Y') ?></td>
<td data-sort="<?= $p_date->format('U') ?>" class="td-center"><?= $f_date->format('d F Y') ?></td>
<td class="td-center">
<?php if ($delta->days <= 2): ?>
<i class='far fa-check-square fa-lg' aria-hidden='true'></i>
@ -239,6 +205,7 @@
</tfoot>
<?php } ?>
</table>
<div class="paginator"></div>
</div>
</div>
</div>

View file

@ -14,7 +14,10 @@ if (empty($_GET['user'])) {
$profile_username = trim($_GET['user']);
$profile_info = User::with('favourites')->where('username', $profile_username)->select('id', 'date', 'badge')->first();
$profile_info = User::with('favourites')
->where('username', $profile_username)
->select('id', 'date', 'badge')
->first();
if (!$profile_info) {
// Invalid username
@ -50,7 +53,7 @@ $profile_pastes = $profile_info->pastes;
$profile_favs = $profile_info->favourites;
$is_current_user = ($current_user !== null) && ($profile_info->id == $current_user->id);
updatePageViews($conn);
updatePageViews();
if (isset($_GET['del'])) {
if ($current_user !== null) { // Prevent unauthorized deletes
@ -70,4 +73,5 @@ if (isset($_GET['del'])) {
// Theme
$page_template = 'user_profile';
array_push($script_bundles, 'user_profile');
require_once('theme/' . $default_theme . '/common.php');