Skip to content
This repository has been archived by the owner on Sep 23, 2023. It is now read-only.

Allow wikis to be redirected when deleting #172

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 36 additions & 4 deletions 404.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,41 @@

include "header.php";

echo new \OOUI\MessageWidget( [
'type' => 'error',
'label' => 'Page not found. The wiki you are looking for may have been deleted.'
] );
$redirect = false;

// Check for redirect
$uri = $_SERVER['REQUEST_URI'];
if ( preg_match( '`/wikis/([0-9a-f]{10,32})/`', $uri, $matches, PREG_OFFSET_CAPTURE ) !== false ) {
$wiki = $matches[1][0];
$offset = $matches[1][1];
$wikiData = get_wiki_data( $wiki );
// Follow up to 10 redirect steps
$i = 0;
while ( $wikiData['redirect'] && $i < 10 ) {
$redirect = $wikiData['redirect'];
$wikiData = get_wiki_data( $redirect );
$i++;
}
$redirectUri =
substr( $uri, 0, $offset ) .
$redirect .
substr( $uri, $offset + strlen( $wiki ) );
}

if ( $redirect ) {
echo new \OOUI\MessageWidget( [
'type' => 'info',
'icon' => 'articleRedirect',
'label' => new \OOUI\HtmlSnippet(
'This wiki has been deleted and the following wiki was selected as a direct replacement: ' .
'<a href="' . htmlspecialchars( $redirectUri ) . '" class="wiki">' . substr( $redirect, 0, 10 ) . '</a>'
)
] );
} else {
echo new \OOUI\MessageWidget( [
'type' => 'error',
'label' => 'Page not found. The wiki you are looking for may have been deleted.'
] );
}

include "footer.html";
175 changes: 129 additions & 46 deletions delete.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,57 +11,140 @@
die( '<p>You are not allowed to delete this wiki.</p>' );
}

if ( !isset( $_POST['confirm' ] ) ) {
$patches = format_patch_list( $wikiData['patchList'], $wikiData['branch'] );
$linkedTasks = format_linked_tasks( $wikiData['linkedTaskList'] );
$creator = $wikiData[ 'creator' ] ?? '';
if ( !$wikiData['deleted'] ) {
if ( !isset( $_POST['confirm' ] ) ) {
$patches = format_patch_list( $wikiData['patchList'], $wikiData['branch'] );
$linkedTasks = format_linked_tasks( $wikiData['linkedTaskList'] );
$creator = $wikiData[ 'creator' ] ?? '';

echo '<table class="wikis">' .
'<tr>' .
'<th>Wiki</th>' .
'<th>Patches<br /><em>✓=Merged ✗=Abandoned</em></th>' .
'<th>Linked tasks<br /><em>✓=Resolved ✗=Declined/Invalid</em></th>' .
'<th>Time</th>' .
( $useOAuth ? '<th>Creator</th>' : '' ) .
'</tr>' .
'<tr>' .
'<td data-label="Wiki" class="wiki"><a href="wikis/' . $wiki . '/w" title="' . $wiki . '">' . substr( $wiki, 0, 10 ) . '</a></td>' .
'<td data-label="Patches" class="patches">' . $patches . '</td>' .
'<td data-label="Linked tasks" class="linkedTasks">' . $linkedTasks . '</td>' .
'<td data-label="Time" class="date">' . date( 'Y-m-d H:i:s', $wikiData[ 'created' ] ) . '</td>' .
( $useOAuth ? '<td data-label="Creator">' . ( $creator ? user_link( $creator ) : '?' ) . '</td>' : '' ) .
'</tr>' .
'</table>';
echo '<table class="wikis">' .
'<tr>' .
'<th>Wiki</th>' .
'<th>Patches<br /><em>✓=Merged ✗=Abandoned</em></th>' .
'<th>Linked tasks<br /><em>✓=Resolved ✗=Declined/Invalid</em></th>' .
'<th>Time</th>' .
( $useOAuth ? '<th>Creator</th>' : '' ) .
'</tr>' .
'<tr>' .
'<td data-label="Wiki" class="wiki"><a href="wikis/' . $wiki . '/w" title="' . $wiki . '">' . substr( $wiki, 0, 10 ) . '</a></td>' .
'<td data-label="Patches" class="patches">' . $patches . '</td>' .
'<td data-label="Linked tasks" class="linkedTasks">' . $linkedTasks . '</td>' .
'<td data-label="Time" class="date">' . date( 'Y-m-d H:i:s', $wikiData[ 'created' ] ) . '</td>' .
( $useOAuth ? '<td data-label="Creator">' . ( $creator ? user_link( $creator ) : '?' ) . '</td>' : '' ) .
'</tr>' .
'</table>';

echo '<form method="POST">' .
'<p>Are you sure you want to delete this wiki?</p>' .
'<p>This cannot be undone.</p>' .
new OOUI\ButtonInputWidget( [
'type' => 'submit',
'name' => 'confirm',
'label' => 'Delete',
'flags' => [ 'primary', 'destructive' ]
] ) .
new OOUI\HiddenInputWidget( [
'name' => 'csrf_token',
'value' => get_csrf_token(),
] ) .
'</form>';
die();
}
$username = $user ? $user->username : null;
$wikilist = [
[
'data' => '',
'label' => 'None',
]
];
$stmt = $mysqli->prepare( '
SELECT wiki, creator, UNIX_TIMESTAMP( created ) created
FROM wikis
WHERE !deleted
ORDER BY IF( creator = ?, 1, 0 ) DESC, created DESC
' );
if ( !$stmt ) {
die( $mysqli->error );
}
$stmt->bind_param( 's', $username );
$stmt->execute();
$results = $stmt->get_result();
if ( !$results ) {
die( $mysqli->error );
}
$shownMyWikis = false;
$shownOtherWikis = false;
while ( $data = $results->fetch_assoc() ) {
if ( $data[ 'wiki' ] === $wiki ) {
continue;
}
$creator = $data[ 'creator' ] ?? '';
if ( !$shownMyWikis && $creator === $username ) {
$wikilist[] = [ 'optgroup' => 'My wikis' ];
$shownMyWikis = true;
}
if ( $shownMyWikis && !$shownOtherWikis && $creator !== $username ) {
$wikilist[] = [ 'optgroup' => 'Other wikis' ];
$shownOtherWikis = true;
}
$wikilist[] = [
'data' => $data[ 'wiki' ],
'label' => substr( $data[ 'wiki' ], 0, 10 ) . ' - ' . $data[ 'creator' ] . ' (' . date( 'Y-m-d H:i:s', $data[ 'created' ] ) . ')',
];
}
echo new OOUI\FormLayout( [
'method' => 'POST',
'items' => [
new OOUI\FieldsetLayout( [
'label' => new OOUI\HtmlSnippet(
'<br>Are you sure you want to delete this wiki? This cannot be undone.'
),
'items' => array_filter( [
count( $wikilist ) > 1 ?
new OOUI\FieldLayout(
new OOUI\DropdownInputWidget( [
'name' => 'redirect',
'options' => $wikilist,
] ),
[
'label' => 'Leave a redirect to another wiki (optional):',
'align' => 'left',
]
) :
null,
new OOUI\FieldLayout(
new OOUI\ButtonInputWidget( [
'type' => 'submit',
'name' => 'confirm',
'label' => 'Delete',
'flags' => [ 'primary', 'destructive' ]
] ),
[
'label' => ' ',
'align' => 'left',
]
),
new OOUI\FieldLayout(
new OOUI\HiddenInputWidget( [
'name' => 'csrf_token',
'value' => get_csrf_token(),
] )
),
] )
] )
]
] );

if ( !isset( $_POST['csrf_token'] ) || !check_csrf_token( $_POST['csrf_token'] ) ) {
die( "Invalid session." );
}
} else {
if ( !isset( $_POST['csrf_token'] ) || !check_csrf_token( $_POST['csrf_token'] ) ) {
die( "Invalid session." );
}

$redirect = $_POST['redirect'] ?: null;

ob_implicit_flush( true );

ob_implicit_flush( true );
echo '<div class="consoleLog">';
$error = delete_wiki( $wiki, $redirect );
echo '</div>';

echo '<div class="consoleLog">';
$error = delete_wiki( $wiki );
echo '</div>';
if ( $error ) {
die( '<p>Error deleting wiki:<br>' . htmlentities( $error ) . '</p>' );
}

if ( $error ) {
die( '<p>Error deleting wiki:<br>' . htmlentities( $error ) . '</p>' );
} else {
// Refresh wiki data
$wikiData = get_wiki_data( $wiki );
}
}

if ( $wikiData['deleted'] ) {
echo '<p>Wiki deleted.</p>';
}

if ( $wikiData['redirect'] ) {
echo '<p>Redirected to <a href="wikis/' . $wikiData['redirect'] . '/w">' . $wikiData['redirect'] . '</a>.</p>';
}
20 changes: 14 additions & 6 deletions includes.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function get_wiki_data( string $wiki ): array {
global $mysqli;

$stmt = $mysqli->prepare( '
SELECT wiki, creator, UNIX_TIMESTAMP( created ) created, patches, branch, announcedTasks, timeToCreate, deleted
SELECT wiki, creator, UNIX_TIMESTAMP( created ) created, patches, branch, announcedTasks, timeToCreate, deleted, redirect
FROM wikis WHERE wiki = ?
' );
if ( !$stmt ) {
Expand Down Expand Up @@ -316,7 +316,11 @@ function shell( $cmd, array $env = [] ): ?string {
return $error ? null : $process->getOutput();
}

function delete_wiki( string $wiki ): int {
function is_valid_hash( string $hash ): bool {
return preg_match( '/^[0-9a-f]{10,32}$/', $hash ) !== false;
}

function delete_wiki( string $wiki, ?string $redirect = null ): ?string {
global $mysqli;

$wikiData = get_wiki_data( $wiki );
Expand All @@ -325,7 +329,7 @@ function delete_wiki( string $wiki ): int {
return 'Wiki already deleted.';
}

$error = shell_echo( __DIR__ . '/deletewiki.sh',
$errorCode = shell_echo( __DIR__ . '/deletewiki.sh',
[
'PATCHDEMO' => __DIR__,
'WIKI' => $wiki
Expand All @@ -346,16 +350,20 @@ function delete_wiki( string $wiki ): int {
);
}

if ( $redirect && !is_valid_hash( $redirect ) ) {
$redirect = null;
}

$stmt = $mysqli->prepare( '
UPDATE wikis
SET deleted = 1
SET deleted = 1, redirect = ?
WHERE wiki = ?
' );
$stmt->bind_param( 's', $wiki );
$stmt->bind_param( 'ss', $redirect, $wiki );
$stmt->execute();
$stmt->close();

return $error;
return $errorCode ? 'Delete script failed.' : null;
}

$requestCache = [];
Expand Down
3 changes: 3 additions & 0 deletions sql/patchdemo.sql
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ ALTER TABLE `tasks`

ALTER TABLE `wikis`
ADD COLUMN IF NOT EXISTS `branch` VARCHAR(64) NOT NULL AFTER `patches`;

ALTER TABLE `wikis`
ADD COLUMN IF NOT EXISTS `redirect` VARCHAR(32) NULL AFTER `deleted`;