our $dbiuser = undef;
our $dbipass = undef;
+# For manual moves made from the web interface.
+our $adminpass = undef;
+
eval {
my $config_filename = $ENV{'REMOTEGLOT_CONFIG'} // 'config.local.pm';
require $config_filename;
if ($pgn->result eq '1-0' || $pgn->result eq '1/2-1/2' || $pgn->result eq '0-1') {
$pos->{'result'} = $pgn->result;
}
- $pos->{'history'} = \@repretty_moves;
+ my @extra_moves = ();
+ $pos = extend_from_manual_override($pos, \@repretty_moves, \@extra_moves);
extract_clock($pgn, $pos);
+ $pos->{'history'} = \@repretty_moves;
+ $pos->{'extra_moves'} = \@extra_moves;
# Sometimes, PGNs lose a move or two for a short while,
# or people push out new ones non-atomically.
}
return unless (exists($pos_calculating->{'board'}));
+
+ my $extra_moves = $pos_calculating->{'extra_moves'};
+ if (defined($extra_moves) && scalar @$extra_moves > 0) {
+ $text .= " Manual move extensions: " . join(' ', @$extra_moves) . "\n";
+ }
if (exists($info->{'pv1'}) && exists($info->{'pv2'})) {
# multi-PV
return undef;
}
+sub extend_from_manual_override {
+ my ($pos, $moves, $extra_moves) = @_;
+
+ my $q = $dbh->prepare('SELECT next_move FROM game_extensions WHERE fen=? AND history=? AND player_w=? AND player_b=? AND (CURRENT_TIMESTAMP - ts) < INTERVAL \'1 hour\'');
+ while (1) {
+ my $player_w = $pos->{'player_w'};
+ my $player_b = $pos->{'player_b'};
+ if ($player_w =~ /^base64:(.*)$/) {
+ $player_w = MIME::Base64::decode_base64($1);
+ }
+ if ($player_b =~ /^base64:(.*)$/) {
+ $player_b = MIME::Base64::decode_base64($1);
+ }
+ #use Data::Dumper; print Dumper([$pos->fen(), JSON::XS::encode_json($moves), $player_w, $player_b]);
+ $q->execute($pos->fen(), JSON::XS::encode_json($moves), $player_w, $player_b);
+ my $ref = $q->fetchrow_hashref;
+ if (defined($ref)) {
+ my $move = $ref->{'next_move'};
+ ($pos) = $pos->make_pretty_move($move);
+ push @$moves, $move;
+ push @$extra_moves, $move;
+ } else {
+ last;
+ }
+ }
+ return $pos;
+}
+
sub extract_clock {
my ($pgn, $pos) = @_;
/** @type {?number} @private */
let unique = null;
+/** @type {?string} @private */
+let admin_password = null;
+
/** @type {boolean} @private */
let enable_sound = false;
} else {
document.getElementById("searchstats").textContent = "";
}
+ if (admin_password !== null) {
+ document.getElementById("searchstats").innerHTML += " | <span style=\"color: red;\">ADMIN MODE (if password is right)</span>";
+ }
// Update the board itself.
base_fen = data['position']['fen'];
promotion: 'q' // NOTE: always promote to a queen for example simplicity
});
+ if (admin_password !== null) {
+ let url = '/manual-override.pl';
+ url += '?fen=' + encodeURIComponent(display_fen);
+ url += '&history=' + encodeURIComponent(JSON.stringify(current_analysis_data['position']['history']));
+ url += '&move=' + encodeURIComponent(move.san);
+ url += '&player_w=' + encodeURIComponent(current_analysis_data['position']['player_w']);
+ url += '&player_b=' + encodeURIComponent(current_analysis_data['position']['player_b']);
+ url += '&password=' + encodeURIComponent(admin_password);
+ fetch(url);
+ return;
+ }
+
// Move ahead on the line we're on -- this includes history if we've
// gone backwards.
if (current_display_line &&
set_sound(false);
}
+ let admin_match = window.location.href.match(/\?password=([a-zA-Z0-9_-]+)/);
+ if (admin_match !== null) {
+ admin_password = admin_match[1];
+ }
+
// Create board.
board = new window.ChessBoard('board', {
onMoveEnd: function() { board_is_animating = false; },
--- /dev/null
+#! /usr/bin/perl
+use strict;
+use warnings;
+use DBI;
+use DBD::Pg;
+use CGI;
+use Encode;
+use lib qw(..);
+require 'config.pm';
+
+my $dbh = DBI->connect($remoteglotconf::dbistr, $remoteglotconf::dbiuser, $remoteglotconf::dbipass)
+ or die DBI->errstr;
+$dbh->{RaiseError} = 1;
+
+my $cgi = CGI->new;
+my $password = Encode::decode_utf8($cgi->param('password'));
+if (!defined($password) || $password ne $remoteglotconf::adminpass) {
+ print CGI->header(-type=>'text/plain; charset=utf-8', -status=>'403 Denied');
+ print "Nope.\n";
+ exit;
+}
+
+$dbh->do('INSERT INTO game_extensions ( fen, history, player_w, player_b, ts, next_move ) VALUES ( ?, ?, ?, ?, CURRENT_TIMESTAMP, ? )',
+ undef,
+ Encode::decode_utf8($cgi->param('fen')),
+ Encode::decode_utf8($cgi->param('history')),
+ Encode::decode_utf8($cgi->param('player_w')),
+ Encode::decode_utf8($cgi->param('player_b')),
+ Encode::decode_utf8($cgi->param('move')));
+system("touch", $remoteglotconf::json_output);
+
+print CGI->header(-type=>'text/plain; charset=utf-8');
+print "OK\n";