diff --git a/Vagrantfile b/Vagrantfile index 6e0dc3dd..0a3b30f7 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -12,5 +12,6 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.provider "virtualbox" do |v| v.memory = 4096 v.cpus = 4 + v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"] end end diff --git a/database/schema.sql b/database/schema.sql index 3c80338e..97021497 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -90,6 +90,9 @@ CREATE TABLE `attachments` ( `created_ts` timestamp NOT NULL DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; + +-- Temp Fix by having a dummy row to prevent constant SELECT queries +INSERT INTO attachments (filename, type, level_id, created_ts) VALUES ("test", "text/plain", 0, NOW()); /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -257,8 +260,8 @@ INSERT INTO `configuration` (field, value, description) VALUES("login_strongpass INSERT INTO `configuration` (field, value, description) VALUES("login_facebook", "0", "(Boolean) Allow Facebook Login"); INSERT INTO `configuration` (field, value, description) VALUES("login_google", "0", "(Boolean) Allow Google Login"); INSERT INTO `configuration` (field, value, description) VALUES("password_type", "1", "(Integer) Type of passwords: See table password_types"); -INSERT INTO `configuration` (field, value, description) VALUES("default_bonus", "30", "(Integer) Default value for bonus in levels"); -INSERT INTO `configuration` (field, value, description) VALUES("default_bonusdec", "10", "(Integer) Default bonus decrement in levels"); +INSERT INTO `configuration` (field, value, description) VALUES("default_bonus", "0", "(Integer) Default value for bonus in levels"); +INSERT INTO `configuration` (field, value, description) VALUES("default_bonusdec", "0", "(Integer) Default bonus decrement in levels"); INSERT INTO `configuration` (field, value, description) VALUES("language", "en", "(String) Language of the system"); INSERT INTO `configuration` (field, value, description) VALUES("livesync", "0", "(Boolean) LiveSync functionality"); INSERT INTO `configuration` (field, value, description) VALUES("livesync_auth_key", "", "(String) Optional LiveSync Auth Key"); diff --git a/extra/lib.sh b/extra/lib.sh index 9dbeddca..6897239c 100755 --- a/extra/lib.sh +++ b/extra/lib.sh @@ -228,6 +228,7 @@ function install_hhvm() { local __multiservers=$3 package software-properties-common + package apt-transport-https log "Adding HHVM keys" sudo DEBIAN_FRONTEND=noninteractive apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0x5a16e7281be7a449 diff --git a/extra/nginx.conf b/extra/nginx.conf index c2a8b55a..dc3c4155 100644 --- a/extra/nginx.conf +++ b/extra/nginx.conf @@ -31,7 +31,7 @@ server { add_header X-Content-Type-Options nosniff; add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; - add_header Cache-Control "no-cache, no-store"; + add_header Cache-Control "no-cache"; add_header Pragma "no-cache"; expires -1; diff --git a/extra/nginx/nginx.conf b/extra/nginx/nginx.conf index c5edb099..66636c94 100644 --- a/extra/nginx/nginx.conf +++ b/extra/nginx/nginx.conf @@ -31,7 +31,7 @@ server { add_header X-Content-Type-Options nosniff; add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; - add_header Cache-Control "no-cache, no-store"; + add_header Cache-Control "no-cache"; add_header Pragma "no-cache"; expires -1; diff --git a/extra/provision.sh b/extra/provision.sh index 00b15291..a25e981e 100755 --- a/extra/provision.sh +++ b/extra/provision.sh @@ -215,6 +215,7 @@ package_repo_update package git package curl package rsync +package unzip # Check for available memory, should be over 1GB AVAILABLE_RAM=`free -mt | grep Total | awk '{print $2}'` diff --git a/package.json b/package.json index 5d9be93e..b2043931 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "d3": "^3.5.16", "dropkickjs": "2.1.10", "hoverintent-jqplugin": "^0.2.1", - "jquery": "^2.2.3", + "jquery": "^3.0.0", "keycode": "^2.1.1", "typed.js": "^1.1.1", "bxslider": "4.2.6" diff --git a/src/Router.php b/src/Router.php index bffaf9a9..6d23295e 100644 --- a/src/Router.php +++ b/src/Router.php @@ -81,7 +81,7 @@ class Router { case 'logout': // TODO: Make a confirmation modal? SessionUtils::sessionLogout(); - invariant(false, 'should not reach here'); + return await (new IndexController())->genRender(); default: throw new NotFoundRedirectException(); } diff --git a/src/SessionUtils.php b/src/SessionUtils.php index fe0d0301..26b9b15b 100644 --- a/src/SessionUtils.php +++ b/src/SessionUtils.php @@ -98,8 +98,6 @@ public static function sessionLogout(): void { $params["httponly"], ); session_destroy(); - - throw new IndexRedirectException(); } public static function sessionActive(): bool { diff --git a/src/controllers/AdminController.php b/src/controllers/AdminController.php index d8c002be..e8d860b4 100644 --- a/src/controllers/AdminController.php +++ b/src/controllers/AdminController.php @@ -251,7 +251,7 @@ class="fb--conf--language" $team = await MultiTeam::genTeam($token->getTeamId()); // TODO: Combine Awaits $token_status = - {tr('Used by')} {$team->getName()} + {tr('Used by')} {$team->getName()} ; } else { $token_status = @@ -410,11 +410,11 @@ class="fb-cta cta--yellow" if ($start_ts->getValue() !== '0' && $start_ts->getValue() !== 'NaN') { $game_start_ts = $start_ts->getValue(); $game_start_array = array(); - $game_start_array['year'] = gmdate('Y', $game_start_ts); - $game_start_array['mon'] = gmdate('m', $game_start_ts); - $game_start_array['mday'] = gmdate('d', $game_start_ts); - $game_start_array['hours'] = gmdate('H', $game_start_ts); - $game_start_array['minutes'] = gmdate('i', $game_start_ts); + $game_start_array['year'] = date('Y', $game_start_ts); + $game_start_array['mon'] = date('m', $game_start_ts); + $game_start_array['mday'] = date('d', $game_start_ts); + $game_start_array['hours'] = date('H', $game_start_ts); + $game_start_array['minutes'] = date('i', $game_start_ts); } else { $game_start_ts = '0'; $game_start_array['year'] = '0'; @@ -428,11 +428,11 @@ class="fb-cta cta--yellow" if ($end_ts->getValue() !== '0' && $end_ts->getValue() !== 'NaN') { $game_end_ts = $end_ts->getValue(); $game_end_array = array(); - $game_end_array['year'] = gmdate('Y', $game_end_ts); - $game_end_array['mon'] = gmdate('m', $game_end_ts); - $game_end_array['mday'] = gmdate('d', $game_end_ts); - $game_end_array['hours'] = gmdate('H', $game_end_ts); - $game_end_array['minutes'] = gmdate('i', $game_end_ts); + $game_end_array['year'] = date('Y', $game_end_ts); + $game_end_array['mon'] = date('m', $game_end_ts); + $game_end_array['mday'] = date('d', $game_end_ts); + $game_end_array['hours'] = date('H', $game_end_ts); + $game_end_array['minutes'] = date('i', $game_end_ts); } else { $game_end_ts = '0'; $game_end_array['year'] = '0'; @@ -1033,6 +1033,7 @@ class={strval($game_schedule_reset_class)} type="number" value={strval($game_start_array['year'])} name="fb--schedule--start_year" + tabindex="1" />
@@ -1041,6 +1042,7 @@ class={strval($game_schedule_reset_class)} type="number" value={strval($game_end_array['year'])} name="fb--schedule--end_year" + tabindex="6" />
@@ -1051,6 +1053,7 @@ class={strval($game_schedule_reset_class)} type="number" value={strval($game_start_array['mon'])} name="fb--schedule--start_month" + tabindex="2" />
@@ -1059,6 +1062,7 @@ class={strval($game_schedule_reset_class)} type="number" value={strval($game_end_array['mon'])} name="fb--schedule--end_month" + tabindex="7" />
@@ -1069,6 +1073,7 @@ class={strval($game_schedule_reset_class)} type="number" value={strval($game_start_array['mday'])} name="fb--schedule--start_day" + tabindex="3" />
@@ -1077,6 +1082,7 @@ class={strval($game_schedule_reset_class)} type="number" value={strval($game_end_array['mday'])} name="fb--schedule--end_day" + tabindex="8" />
@@ -1087,6 +1093,7 @@ class={strval($game_schedule_reset_class)} type="number" value={strval($game_start_array['hours'])} name="fb--schedule--start_hour" + tabindex="4" />
@@ -1095,6 +1102,7 @@ class={strval($game_schedule_reset_class)} type="number" value={strval($game_end_array['hours'])} name="fb--schedule--end_hour" + tabindex="9" />
@@ -1105,6 +1113,7 @@ class={strval($game_schedule_reset_class)} type="number" value={strval($game_start_array['minutes'])} name="fb--schedule--start_min" + tabindex="5" />
@@ -1113,6 +1122,7 @@ class={strval($game_schedule_reset_class)} type="number" value={strval($game_end_array['minutes'])} name="fb--schedule--end_min" + tabindex="10" />
diff --git a/src/controllers/IndexController.php b/src/controllers/IndexController.php index 10f9971f..cf195943 100644 --- a/src/controllers/IndexController.php +++ b/src/controllers/IndexController.php @@ -131,7 +131,7 @@ class="fb-cta cta--yellow"> $next_game_text = tr('Soon'); $countdown = array('--', '--', '--', '--'); } else { - $next_game_text = date(tr('date and time format'), $next_game); + $next_game_text = date('H:i:s T D m/d/y', $next_game); $game_start = new DateTime(); $game_start->setTimestamp(intval($next_game)); $now = new DateTime('now'); diff --git a/src/controllers/ajax/IndexAjaxController.php b/src/controllers/ajax/IndexAjaxController.php index 679032af..d60368cd 100644 --- a/src/controllers/ajax/IndexAjaxController.php +++ b/src/controllers/ajax/IndexAjaxController.php @@ -252,7 +252,7 @@ protected function getActions(): array { // Check if login is disabled and this isn't an admin if (($login->getValue() === '0') && ($team === null || $team->getAdmin() === false)) { - return Utils::error_response('Login failed', 'login'); + return Utils::error_response('Login closed', 'login'); } // Otherwise let's login any valid attempt diff --git a/src/controllers/modals/CountryModalController.php b/src/controllers/modals/CountryModalController.php index c537c51f..4ca4cdcf 100644 --- a/src/controllers/modals/CountryModalController.php +++ b/src/controllers/modals/CountryModalController.php @@ -49,7 +49,7 @@ class CountryModalController extends ModalController { {tr('PTS')}
-
+
{tr('type')}
{tr('category')}
@@ -86,7 +86,7 @@ class CountryModalController extends ModalController {
-
@@ -141,13 +141,13 @@ class=
+ "col country-capture-stats fb-column-container">
{tr('PTS')}
-
-
+
+
{tr('type')}
@@ -159,12 +159,6 @@ class=
-
- {tr('completed_by')} > -
    -
    ; @@ -185,7 +179,7 @@ class= -
    @@ -237,13 +231,13 @@ class=
    + "col country-capture-stats fb-column-container">
    {tr('PTS')}
    -
    -
    +
    +
    {tr('type')}
    @@ -255,12 +249,6 @@ class=
    -
    - {tr('completed_by')} > -
      -
      ; } diff --git a/src/data/country-data.php b/src/data/country-data.php index 204fbe36..1d800657 100644 --- a/src/data/country-data.php +++ b/src/data/country-data.php @@ -31,7 +31,7 @@ class CountryDataController extends DataController { $level->getId(), ), 'links_list' => Link::genAllLinksValues($level->getId()), - 'completed_by' => MultiTeam::genCompletedLevelTeamNames( + 'completed' => MultiTeam::genCompletedLevel( $level->getId(), ), }; @@ -41,7 +41,7 @@ class CountryDataController extends DataController { $category = $awaitables_results['category']; $attachments_list = $awaitables_results['attachments_list']; $links_list = $awaitables_results['links_list']; - $completed_by = $awaitables_results['completed_by']; + $completed = $awaitables_results['completed']; invariant( $country instanceof Country, @@ -52,10 +52,6 @@ class CountryDataController extends DataController { 'category should be of type Category', ); - if (!$country) { - continue; - } - if ($level->getHint() !== '') { // There is hint, can this team afford it? if ($level->getPenalty() > $my_team->getPoints()) { // Not enough points @@ -89,7 +85,7 @@ class CountryDataController extends DataController { } // Who is the first owner of this level - if ($completed_by) { + if ($completed) { $owner = await MultiTeam::genFirstCapture($level->getId()); // TODO: Combine Awaits $owner = $owner->getName(); } else { @@ -104,7 +100,7 @@ class CountryDataController extends DataController { 'bonus' => $level->getBonus(), 'category' => $category->getCategory(), 'owner' => $owner, - 'completed' => $completed_by, + 'completed' => $completed, 'hint' => $hint, 'hint_cost' => $hint_cost, 'attachments' => $attachments_list, diff --git a/src/inc/gameboard/modules/leaderboard.php b/src/inc/gameboard/modules/leaderboard.php index bc634f0a..aaf0c891 100644 --- a/src/inc/gameboard/modules/leaderboard.php +++ b/src/inc/gameboard/modules/leaderboard.php @@ -13,7 +13,7 @@ class LeaderboardModuleController extends ModuleController { $leaderboard_ul = ; list($my_team, $my_rank, $gameboard) = await \HH\Asio\va( - MultiTeam::genTeam(SessionUtils::sessionTeam()), + MultiTeam::genTeam(SessionUtils::sessionTeam(), TRUE), Team::genMyRank(SessionUtils::sessionTeam()), Configuration::gen('gameboard'), ); diff --git a/src/language/language.php b/src/language/language.php index ab5a8b84..003ee1d4 100644 --- a/src/language/language.php +++ b/src/language/language.php @@ -6,6 +6,7 @@ async function tr_start(): Awaitable { $config = await Configuration::gen('language'); + global $language; // temporary fix $language = $config->getValue(); $document_root = must_have_string(Utils::getSERVER(), 'DOCUMENT_ROOT'); if (preg_match('/^[^,;]+$/', $language) && @@ -28,8 +29,12 @@ function tr(string $word): string { /* HH_IGNORE_ERROR[2049] */ /* HH_IGNORE_ERROR[4106] */ global $lang; + global $language; /* HH_IGNORE_ERROR[2050] */ - if (array_key_exists($word, $lang)) { + if ($language === 'en' && $word != 'date and time format') { // temporary fix for + return $word; // reducing function calls to + } // tr() + elseif (array_key_exists($word, $lang)) { /* HH_IGNORE_ERROR[2050] */ return $lang[$word]; } else { @@ -38,4 +43,4 @@ function tr(string $word): string { ); return $word; } -} +} \ No newline at end of file diff --git a/src/models/Category.php b/src/models/Category.php index f101cf6a..7e6af789 100644 --- a/src/models/Category.php +++ b/src/models/Category.php @@ -90,7 +90,6 @@ private static function categoryFromRow(Map $row): Category { } self::setMCRecords('ALL_CATEGORIES', $categories); return $categories; - return $categories; } else { invariant( is_array($mc_result), @@ -105,13 +104,13 @@ private static function categoryFromRow(Map $row): Category { $db = await self::genDb(); $result = await $db->queryf( - 'SELECT COUNT(*) FROM levels WHERE category_id = %d', + 'SELECT EXISTS(SELECT * FROM levels WHERE category_id = %d)', $category_id, ); if ($result->numRows() > 0) { invariant($result->numRows() === 1, 'Expected exactly one result'); - return intval($result->mapRows()[0]['COUNT(*)']) > 0; + return intval($result->mapRows()[0]->firstValue()) > 0; } else { return false; } @@ -236,13 +235,13 @@ private static function categoryFromRow(Map $row): Category { $db = await self::genDb(); $result = await $db->queryf( - 'SELECT COUNT(*) FROM categories WHERE category = %s', + 'SELECT EXISTS(SELECT * FROM categories WHERE category = %s)', $category, ); if ($result->numRows() > 0) { invariant($result->numRows() === 1, 'Expected exactly one result'); - return (intval(idx($result->mapRows()[0], 'COUNT(*)')) > 0); + return intval($result->mapRows()[0]->firstValue()) > 0; } else { return false; } diff --git a/src/models/Configuration.php b/src/models/Configuration.php index 25f1623f..b7e573da 100644 --- a/src/models/Configuration.php +++ b/src/models/Configuration.php @@ -107,13 +107,13 @@ public function getDescription(): string { public static async function genValidField(string $field): Awaitable { $db = await self::genDb(); $result = await $db->queryf( - 'SELECT COUNT(*) FROM configuration WHERE field = %s', + 'SELECT EXISTS(SELECT * FROM configuration WHERE field = %s)', $field, ); invariant($result->numRows() === 1, 'Expected exactly one result'); - return intval(idx(firstx($result->mapRows()), 'COUNT(*)')) > 0; + return intval($result->mapRows()[0]->firstValue()) > 0; } // All the password types. diff --git a/src/models/Control.php b/src/models/Control.php index 93c6b7a1..e8a9caf9 100644 --- a/src/models/Control.php +++ b/src/models/Control.php @@ -75,6 +75,7 @@ class Control extends Model { self::genResetBases(), // Clear bases log self::genClearScriptLog(), Configuration::genUpdate('registration', '0'), // Disable registration + Configuration::genUpdate('login', '1'), // Enable login ); await \HH\Asio\va( diff --git a/src/models/Country.php b/src/models/Country.php index 75fad5cc..cb5a434d 100644 --- a/src/models/Country.php +++ b/src/models/Country.php @@ -316,32 +316,13 @@ private static function countryFromRow(Map $row): Country { $db = await self::genDb(); $result = await $db->queryf( - 'SELECT COUNT(*) FROM countries WHERE iso_code = %s', + 'SELECT EXISTS(SELECT * FROM countries WHERE iso_code = %s)', $country, ); if ($result->numRows() > 0) { invariant($result->numRows() === 1, 'Expected exactly one result'); - return (intval(idx($result->mapRows()[0], 'COUNT(*)')) > 0); - } else { - return false; - } - } - - // Check if a country already exists, by id - public static async function genCheckExistsById( - int $entity_id, - ): Awaitable { - $db = await self::genDb(); - - $result = await $db->queryf( - 'SELECT COUNT(*) FROM countries WHERE id = %d', - $entity_id, - ); - - if ($result->numRows() > 0) { - invariant($result->numRows() === 1, 'Expected exactly one result'); - return (intval(idx($result->mapRows()[0], 'COUNT(*)')) > 0); + return intval($result->mapRows()[0]->firstValue()) > 0; } else { return false; } diff --git a/src/models/HintLog.php b/src/models/HintLog.php index 9e8d1dc5..c0d10361 100644 --- a/src/models/HintLog.php +++ b/src/models/HintLog.php @@ -64,6 +64,8 @@ private static function hintlogFromRow(Map $row): HintLog { public static async function genResetHints(): Awaitable { $db = await self::genDb(); await $db->queryf('DELETE FROM hints_log WHERE id > 0'); + // Temp fix by having a dummy row + await $db->query('INSERT INTO hints_log (ts, level_id, team_id, penalty) VALUES (NOW(), 0, 0, 0)'); } // Check if there is a previous hint. diff --git a/src/models/Level.php b/src/models/Level.php index e559621b..68c88603 100644 --- a/src/models/Level.php +++ b/src/models/Level.php @@ -722,6 +722,7 @@ private static function levelFromRow(Map $row): Level { $action = ($active === true) ? "enabled" : "disabled"; $country_id = await self::genCountryIdForLevel($level_id); $country = await Country::gen($country_id); + await Country::genSetStatus($country_id, true); await \HH\Asio\va( ActivityLog::genAdminLog($action, "Country", $country_id), Announcement::genCreateAuto($country->getName().' '.$action.'!'), @@ -1201,14 +1202,16 @@ private static function levelFromRow(Map $row): Level { } // Adjust points and log the hint - await \HH\Asio\va( - $db->queryf( - 'UPDATE teams SET points = points - %d WHERE id = %d LIMIT 1', - $penalty, - $team_id, - ), - HintLog::genLogGetHint($level_id, $team_id, $penalty), - ); + if (!$hint) { + await \HH\Asio\va( + $db->queryf( + 'UPDATE teams SET points = points - %d WHERE id = %d LIMIT 1', + $penalty, + $team_id, + ), + HintLog::genLogGetHint($level_id, $team_id, $penalty), + ); + } ActivityLog::invalidateMCRecords('ALL_ACTIVITY'); // Invalidate Memcached ActivityLog data. MultiTeam::invalidateMCRecords('ALL_TEAMS'); // Invalidate Memcached MultiTeam data. @@ -1313,7 +1316,7 @@ public static function getBasesResponses( $result = await $db->queryf( - 'SELECT COUNT(*) FROM levels WHERE type = %s AND title = %s AND entity_id IN (SELECT id FROM countries WHERE iso_code = %s)', + 'SELECT EXISTS(SELECT * FROM levels WHERE type = %s AND title = %s AND entity_id IN (SELECT id from countries WHERE iso_code = %s))', $type, $title, $entity_iso_code, @@ -1321,26 +1324,7 @@ public static function getBasesResponses( if ($result->numRows() > 0) { invariant($result->numRows() === 1, 'Expected exactly one result'); - return (intval(idx($result->mapRows()[0], 'COUNT(*)')) > 0); - } else { - return false; - } - } - - // Check if a level already exists by type, title and entity. - public static async function genAlreadyExistById( - int $level_id, - ): Awaitable { - $db = await self::genDb(); - - $result = await $db->queryf( - 'SELECT COUNT(*) FROM levels WHERE id = %d', - $level_id, - ); - - if ($result->numRows() > 0) { - invariant($result->numRows() === 1, 'Expected exactly one result'); - return (intval(idx($result->mapRows()[0], 'COUNT(*)')) > 0); + return intval($result->mapRows()[0]->firstValue()) > 0; } else { return false; } @@ -1382,7 +1366,7 @@ public static function getBasesResponses( $db = await self::genDb(); $result = await $db->queryf( - 'SELECT COUNT(*) FROM levels WHERE type = %s AND title = %s AND description = %s AND points = %d', + 'SELECT EXISTS(SELECT * FROM levels WHERE type = %s AND title = %s AND description = %s AND points = %d)', $type, $title, $description, @@ -1390,7 +1374,7 @@ public static function getBasesResponses( ); if ($result->numRows() > 0) { invariant($result->numRows() === 1, 'Expected exactly one result'); - return (intval(idx($result->mapRows()[0], 'COUNT(*)')) > 0); + return intval($result->mapRows()[0]->firstValue()) > 0; } else { return false; } diff --git a/src/models/MultiTeam.php b/src/models/MultiTeam.php index 862b5b5b..17e14992 100644 --- a/src/models/MultiTeam.php +++ b/src/models/MultiTeam.php @@ -319,17 +319,20 @@ class MultiTeam extends Team { 'SELECT level_id, team_id FROM scores_log WHERE level_id IS NOT NULL ORDER BY ts', ); $team_scores_awaitables = Map {}; + $all_teams = await self::genAllTeamsCache($refresh); + foreach ($scores->items() as $score) { + $team = $all_teams->get(intval($score->get('team_id'))); + invariant($team instanceof Team, 'team should be of type Team and not null'); $team_scores_awaitables->add( Pair { $score->get('level_id'), - self::genTeam(intval($score->get('team_id'))), + $team, }, ); } - $team_scores = await \HH\Asio\m($team_scores_awaitables); - - foreach ($team_scores as $level_id_key => $team) { + + foreach ($team_scores_awaitables as $level_id_key => $team) { if ($team->getActive() === true && $team->getVisible() === true) { $teams_by_completed_level[intval($level_id_key)][] = $team; } diff --git a/src/models/Session.php b/src/models/Session.php index 9eca7884..e0cb239e 100644 --- a/src/models/Session.php +++ b/src/models/Session.php @@ -164,11 +164,11 @@ private static function sessionFromRow(Map $row): Session { if (!$mc_result || count($mc_result) === 0 || $refresh) { $db = await self::genDb(); $result = await $db->queryf( - 'SELECT COUNT(*) FROM sessions WHERE cookie = %s', + 'SELECT EXISTS(SELECT * FROM sessions WHERE cookie = %s)', $cookie, ); invariant($result->numRows() === 1, 'Expected exactly one result'); - if (intval(idx($result->mapRows()[0], 'COUNT(*)')) > 0) { + if (intval($result->mapRows()[0]->firstValue()) > 0) { await self::genCreateCacheSession($cookie); return true; } diff --git a/src/models/Team.php b/src/models/Team.php index c9a64fb3..34c3e8e1 100644 --- a/src/models/Team.php +++ b/src/models/Team.php @@ -217,24 +217,6 @@ public static function regenerateHash(string $password_hash): bool { } } - // Check to see if the team is active. - public static async function genCheckTeamStatus( - int $team_id, - ): Awaitable { - $db = await self::genDb(); - $result = await $db->queryf( - 'SELECT COUNT(*) FROM teams WHERE id = %d AND active = 1 LIMIT 1', - $team_id, - ); - - if ($result->numRows() > 0) { - invariant($result->numRows() === 1, 'Expected exactly one result'); - return (intval(idx($result->mapRows()[0], 'COUNT(*)')) > 0); - } else { - return false; - } - } - // Create a team and return the created team id. public static async function genCreate( string $name, @@ -550,30 +532,13 @@ public static function regenerateHash(string $password_hash): bool { $db = await self::genDb(); $result = await $db->queryf( - 'SELECT COUNT(*) FROM teams WHERE name = %s', + 'SELECT EXISTS(SELECT * FROM teams WHERE name = %s)', $team_name, ); if ($result->numRows() > 0) { invariant($result->numRows() === 1, 'Expected exactly one result'); - return (intval(idx($result->mapRows()[0], 'COUNT(*)')) > 0); - } else { - return false; - } - } - - // Check if a team name is already created. - public static async function genTeamExistById( - int $team_id, - ): Awaitable { - $db = await self::genDb(); - - $result = - await $db->queryf('SELECT COUNT(*) FROM teams WHERE id = %d', $team_id); - - if ($result->numRows() > 0) { - invariant($result->numRows() === 1, 'Expected exactly one result'); - return (intval(idx($result->mapRows()[0], 'COUNT(*)')) > 0); + return intval($result->mapRows()[0]->firstValue()) > 0; } else { return false; } @@ -726,16 +691,6 @@ public static function regenerateHash(string $password_hash): bool { ActivityLog::invalidateMCRecords('ALL_ACTIVITY'); // Invalidate Memcached ActivityLog data. } - // Teams total number. - public static async function genTeamsCount(): Awaitable { - $db = await self::genDb(); - - $result = await $db->queryf('SELECT COUNT(*) AS count FROM teams'); - - invariant($result->numRows() === 1, 'Expected exactly one result'); - return intval(idx($result->mapRows()[0], 'COUNT(*)')); - } - public static async function genFirstCapture( int $level_id, ): Awaitable { diff --git a/src/models/Token.php b/src/models/Token.php index a6817aeb..8279a0e1 100644 --- a/src/models/Token.php +++ b/src/models/Token.php @@ -116,13 +116,13 @@ private static function generate(): string { $result = await $db->queryf( - 'SELECT COUNT(*) FROM registration_tokens WHERE used = 0 AND token = %s', + 'SELECT EXISTS(SELECT * FROM registration_tokens WHERE used = 0 AND token = %s)', $token, ); if ($result->numRows() > 0) { invariant($result->numRows() === 1, 'Expected exactly one result'); - return (intval($result->mapRows()[0]['COUNT(*)']) > 0); + return intval($result->mapRows()[0]->firstValue()) > 0; } else { return false; } diff --git a/src/static/css/scss/_gameboard.scss b/src/static/css/scss/_gameboard.scss index b547e6dc..f4a04d54 100644 --- a/src/static/css/scss/_gameboard.scss +++ b/src/static/css/scss/_gameboard.scss @@ -909,7 +909,7 @@ body[data-section="gameboard"] .fb-page { } .country-capture-stats .country-stats { - padding-left: 20px; + padding-left: 50px; } .country-capture-completed { diff --git a/src/static/css/scss/_modals.scss b/src/static/css/scss/_modals.scss index a5e69092..53dcf6c5 100644 --- a/src/static/css/scss/_modals.scss +++ b/src/static/css/scss/_modals.scss @@ -88,6 +88,11 @@ border-left: 1px solid $teal-blue; } + .col dt, .col dd { + width: auto; + display: inline-block; + } + .country-capture-stats { padding: 10px; } diff --git a/src/static/css/scss/_typography.scss b/src/static/css/scss/_typography.scss index 89448df5..447efac6 100644 --- a/src/static/css/scss/_typography.scss +++ b/src/static/css/scss/_typography.scss @@ -521,7 +521,7 @@ dt { font-size: .9em; } -dd { +.country-window dd { font-size: 1.1em; &.country-owner { @@ -544,7 +544,8 @@ dd { } & + dt { - margin-top: 1em; + margin-top: 5%; + margin-left: 10%; } } diff --git a/src/static/js/admin.js b/src/static/js/admin.js index 46c32abb..6310ca24 100644 --- a/src/static/js/admin.js +++ b/src/static/js/admin.js @@ -1057,119 +1057,145 @@ module.exports = { valid; // Route the actions - if (action === 'save') { - valid = validateAdminForm($self); - if (valid) { - saveLevel($section, lockClass); + switch(action) { + case 'save': + valid = validateAdminForm($self); + if (valid) { + saveLevel($section, lockClass); + } + break; + case 'save-no-validation': + saveLevel(); + break; + case 'add-new': + addNewSection($self); + break; + case 'save-category': + updateCategory($section); + break; + case 'create': + valid = validateAdminForm($self); + if (valid) { + createElement($section); + } + break; + case 'create-announcement': + createAnnouncement($section); + break; + case 'export-attachments': + attachmentsExport(); + break; + case 'backup-db': + databaseBackup(); + break; + case 'import-game': + importGame(); + break; + case 'export-game': + exportCurrentGame(); + break; + case 'import-teams': + importTeams(); + break; + case 'export-teams': + exportCurrentTeams(); + break; + case 'import-logos': + importLogos(); + break; + case 'export-logos': + exportCurrentLogos(); + break; + case 'import-levels': + importLevels(); + break; + case 'import-attachments': + importAttachments(); + break; + case 'export-levels': + exportCurrentLevels(); + break; + case 'import-categories': + importCategories(); + break; + case 'export-categories': + exportCurrentCategories(); + break; + case 'flush-memcached': + flushMemcached(); + break; + case 'reset-game-schedule': + resetGameSchedule(); + break; + case 'create-tokens': + createTokens(); + break; + case 'export-tokens': + exportTokens(); + break; + case 'edit': + $section.removeClass(lockClass); + $('input[type="text"], input[type="password"], textarea', $section).prop('disabled', false); + var entity_select = $('[name=entity_id]', $section)[0]; + var category_select = $('[name=category_id]', $section)[0]; + if (entity_select !== undefined) { + Dropkick(entity_select).disable(false); + } + if (category_select !== undefined) { + Dropkick(category_select).disable(false); + } + break; + case 'delete': + $section.remove(); + deleteElement($section); + break; + case 'disable-logo': + toggleLogo($section); + break; + case 'enable-logo': + toggleLogo($section); + break; + case 'disable-country': + toggleCountry($section); + break; + case 'enable-country': + toggleCountry($section); + break; + case 'add-attachment': + addNewAttachment($section); + break; + case 'create-attachment': + $containingDiv = $self.closest('.new-attachment'); + createAttachment($containingDiv); + break; + case 'delete-new-attachment': + $containingDiv = $self.closest('.new-attachment'); + $containingDiv.remove(); + deleteAttachment($containingDiv); + break; + case 'delete-attachment': + $containingDiv = $self.closest('.existing-attachment'); + $containingDiv.remove(); + deleteAttachment($containingDiv); + break; + case 'add-link': + addNewLink($section); + break; + case 'create-link': + $containingDiv = $self.closest('.new-link'); + createLink($containingDiv); + break; + case 'delete-new-link': + $containingDiv = $self.closest('.new-link'); + $containingDiv.remove(); + deleteLink($containingDiv); + break; + case 'delete-link': + $containingDiv = $self.closest('.existing-link'); + $containingDiv.remove(); + deleteLink($containingDiv); + break; } - } else if (action === 'save-no-validation') { - saveLevel(); - } else if (action === 'add-new') { - addNewSection($self); - } else if (action === 'save-category') { - updateCategory($section); - } else if (action === 'create') { - valid = validateAdminForm($self); - if (valid) { - createElement($section); - } - } else if (action === 'create-announcement') { - createAnnouncement($section); - } else if (action === 'export-attachments') { - attachmentsExport(); - } else if (action === 'backup-db') { - databaseBackup(); - } else if (action === 'import-game') { - importGame(); - } else if (action === 'create-tokens') { - createTokens($section); - } else if (action === 'export-tokens') { - exportTokens($section); - } else if (action === 'export-game') { - exportCurrentGame(); - } else if (action === 'import-teams') { - importTeams(); - } else if (action === 'export-teams') { - exportCurrentTeams(); - } else if (action === 'import-logos') { - importLogos(); - } else if (action === 'export-logos') { - exportCurrentLogos(); - } else if (action === 'import-levels') { - importLevels(); - } else if (action === 'import-attachments') { - importAttachments(); - } else if (action === 'export-levels') { - exportCurrentLevels(); - } else if (action === 'import-categories') { - importCategories(); - } else if (action === 'export-categories') { - exportCurrentCategories(); - } else if (action === 'flush-memcached') { - flushMemcached(); - } else if (action === 'reset-game-schedule') { - resetGameSchedule(); - } else if (action === 'create-tokens') { - createTokens(); - } else if (action === 'export-tokens') { - exportTokens(); - } else if (action === 'edit') { - $section.removeClass(lockClass); - $('input[type="text"], input[type="password"], textarea', $section).prop('disabled', false); - var entity_select = $('[name=entity_id]', $section)[0]; - var category_select = $('[name=category_id]', $section)[0]; - if (entity_select !== undefined) { - Dropkick(entity_select).disable(false); - } - if (category_select !== undefined) { - Dropkick(category_select).disable(false); - } - } else if (action === 'delete') { - $section.remove(); - deleteElement($section); - // rename the section boxes - /*$('.admin-box').each(function(i, el){ - var $titleObj = $('.admin-box-header h3', el), - title = $titleObj.text(), - newTitle = title.substring( 0, title.lastIndexOf(" ") + 1 ) + (i + 1); - - $titleObj.text(newTitle); - });*/ - } else if (action === 'disable-logo') { - toggleLogo($section); - } else if (action === 'enable-logo') { - toggleLogo($section); - } else if (action === 'disable-country') { - toggleCountry($section); - } else if (action === 'enable-country') { - toggleCountry($section); - } else if (action === 'add-attachment') { - addNewAttachment($section); - } else if (action === 'create-attachment') { - $containingDiv = $self.closest('.new-attachment'); - createAttachment($containingDiv); - } else if (action === 'delete-new-attachment') { - $containingDiv = $self.closest('.new-attachment'); - $containingDiv.remove(); - deleteAttachment($containingDiv); - } else if (action === 'delete-attachment') { - $containingDiv = $self.closest('.existing-attachment'); - $containingDiv.remove(); - deleteAttachment($containingDiv); - } else if (action === 'add-link') { - addNewLink($section); - } else if (action === 'create-link') { - $containingDiv = $self.closest('.new-link'); - createLink($containingDiv); - } else if (action === 'delete-new-link') { - $containingDiv = $self.closest('.new-link'); - $containingDiv.remove(); - deleteLink($containingDiv); - } else if (action === 'delete-link') { - $containingDiv = $self.closest('.existing-link'); - $containingDiv.remove(); - deleteLink($containingDiv); - } if (actionModal) { Modal.loadPopup('p=action&model=' + actionModal, 'action-' + actionModal, function() { @@ -1222,7 +1248,7 @@ module.exports = { var start_day = $('input[type="number"][name="fb--schedule--start_day"]')[0].value; var start_hour = $('input[type="number"][name="fb--schedule--start_hour"]')[0].value; var start_min = $('input[type="number"][name="fb--schedule--start_min"]')[0].value; - var start_ts = Date.UTC(start_year, start_month - 1, start_day, start_hour, start_min) / 1000; + var start_ts = new Date(start_year, start_month - 1, start_day, start_hour, start_min) / 1000; if ($.isNumeric(start_ts)) { changeConfiguration("start_ts", start_ts); changeConfiguration("next_game", start_ts); @@ -1232,7 +1258,7 @@ module.exports = { var end_day = $('input[type="number"][name="fb--schedule--end_day"]')[0].value; var end_hour = $('input[type="number"][name="fb--schedule--end_hour"]')[0].value; var end_min = $('input[type="number"][name="fb--schedule--end_min"]')[0].value; - var end_ts = Date.UTC(end_year, end_month - 1, end_day, end_hour, end_min) / 1000; + var end_ts = new Date(end_year, end_month - 1, end_day, end_hour, end_min) / 1000; if ($.isNumeric(end_ts)) { changeConfiguration("end_ts", end_ts); } @@ -1503,4 +1529,4 @@ module.exports = { } }); } -}; +}; \ No newline at end of file diff --git a/src/static/js/fb-ctf.js b/src/static/js/fb-ctf.js index a59058cc..c4c8f8c8 100644 --- a/src/static/js/fb-ctf.js +++ b/src/static/js/fb-ctf.js @@ -30,8 +30,7 @@ var filterList = {}; $(document).on('keypress', 'input', function(e) { if (e.keyCode == Keycode.codes['enter']) { e.preventDefault(); - var form_action = $('input[name=action]', e.target.form)[0].value; - if (form_action == 'register_team') { + if (e.target.form[0].value == 'register_team') { Index.registerTeam(); } if (e.target.form[0].value == 'login_team') { @@ -467,6 +466,7 @@ function setupInputListeners() { $.when(mapLoaded, countryDataLoaded).done(function() { renderCountryData(); + refreshMapData(); }); // do stuff when the map and modules are loaded @@ -617,23 +617,6 @@ function setupInputListeners() { $('li', $announcements).remove(); } - /** - * get the owner of the given country, and return the markup - * for rendering somewhere - * - * @param capturedBy (string) - * - the capturing team - */ - function getCapturedByMarkup(capturedBy) { - if (capturedBy === undefined) { - return "Uncaptured"; - } - - var capturedClass = (capturedBy === FB_CTF.data.CONF.currentTeam) ? 'your-name' : 'opponent-name'; - var span = $('').attr('class', capturedClass).text(capturedBy); - return span; - } - /** * automatically scroll through the content on the sidebar * modules. This happens in the "view only" mode @@ -784,7 +767,6 @@ function setupInputListeners() { */ function captureCountry(country) { var $selectCountry = $('.countries .land[title="' + country + '"]', $mapSvg), - capturedBy = getCapturedByMarkup($selectCountry.closest('g').data('captured')), showAnimation = !(is_ie || LIST_VIEW), animationDuration = !showAnimation ? 0 : 600; @@ -824,7 +806,7 @@ function setupInputListeners() { }, animationDuration); } else { setTimeout(function() { - launchCaptureModal(country, capturedBy); + launchCaptureModal(country); }, animationDuration); } } // function countryClick(); @@ -835,9 +817,6 @@ function setupInputListeners() { * @param country (string) * - the country being captured * - * @param capturedBy (string) - * - the user or team who has captured this country - * * @param capturingTeam (string) * - an optional parameter for the team that is attempting * to capture the given country @@ -895,8 +874,6 @@ function setupInputListeners() { * @param country (string) * - the country that is being captured * - * @param capturedBy (string) - * - the user or team who has captured this country */ function launchCaptureModal(country) { var data = FB_CTF.data.COUNTRIES[country]; @@ -1332,7 +1309,7 @@ function setupInputListeners() { var get = $.get(modulePath, function(data) { $self.html(data); - }).error(function(jqxhr, status, error) { + }).fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the module."); console.log(modulePath); console.log(status); @@ -1371,7 +1348,7 @@ function setupInputListeners() { $mapSvg = $('#fb-gameboard-map'); $countryHover = $('[class~="country-hover"]', $mapSvg); enableClickAndDrag.init(); - }, 'html').error(function(jqxhr, status, error) { + }, 'html').fail(function(jqxhr, status, error) { console.error("There was a problem loading the svg map"); console.log(status); console.log(error); @@ -1397,7 +1374,7 @@ function setupInputListeners() { $mapSvg = $('#fb-gameboard-map'); $countryHover = $('[class~="country-hover"]', $mapSvg); enableClickAndDrag.init(); - }, 'html').error(function(jqxhr, status, error) { + }, 'html').fail(function(jqxhr, status, error) { console.error("There was a problem loading the svg map"); console.log(status); console.log(error); @@ -1419,7 +1396,7 @@ function setupInputListeners() { $listview = $('.fb-listview'); $listview.html(data); listviewEventListeners($listview); - }, 'html').error(function(jqxhr, status, error) { + }, 'html').fail(function(jqxhr, status, error) { console.error("There was a problem loading the List View"); console.log(status); console.log(error); @@ -1443,7 +1420,7 @@ function setupInputListeners() { success_callback(); } }) - .error(function(jqxhr, status, error) { + .fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the module."); console.log(loadPath); console.log(status); @@ -1513,7 +1490,7 @@ function setupInputListeners() { FB_CTF.data.TEAMS = data; var df = $.Deferred(); return df.resolve(FB_CTF.data.TEAMS); - }, 'json').error(function(jqxhr, status, error) { + }, 'json').fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the team data."); console.log(loadPath); console.log(status); @@ -1542,7 +1519,7 @@ function setupInputListeners() { FB_CTF.data.CAPTURES = data; var df = $.Deferred(); return df.resolve(FB_CTF.data.CAPTURES); - }, 'json').error(function(jqxhr, status, error) { + }, 'json').fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the captures data."); console.log(loadPath); console.log(status); @@ -1631,7 +1608,7 @@ function setupInputListeners() { FB_CTF.data.CONF = data; var df = $.Deferred(); return df.resolve(FB_CTF.data.CONF); - }, 'json').error(function(jqxhr, status, error) { + }, 'json').fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the conf data."); console.log(loadPath); console.log(status); @@ -1661,7 +1638,7 @@ function setupInputListeners() { console.log("Redirecting to '/index.php?page=login'"); window.location.replace('/index.php?page=login'); } - }).error(function(jqxhr, status, error) { + }).fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the session data."); console.log(loadPath); console.log(status); @@ -1714,6 +1691,7 @@ function setupInputListeners() { $('#' + key)[0].parentNode.children[1].classList.add("captured--you"); //$('#' + key)[0].parentNode.removeAttribute('data-captured'); $('#' + key)[0].parentNode.setAttribute('data-captured', value.datacaptured); + $('#' + key)[0].parentNode.setAttribute('data-status', 'completed'); } else if (value.captured == 'opponent') { //$('#' + key)[0].parentNode.children[1].classList.remove("captured--you"); $('#' + key)[0].parentNode.children[1].classList.add("captured--opponent"); @@ -1721,7 +1699,7 @@ function setupInputListeners() { $('#' + key)[0].parentNode.setAttribute('data-captured', value.datacaptured); } }); - }, 'json').error(function(jqxhr, status, error) { + }, 'json').fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the map data."); console.log(loadPath); console.log(status); @@ -1753,7 +1731,7 @@ function setupInputListeners() { $('#' + key)[0].parentNode.children[1].classList.remove("captured--you"); $('#' + key)[0].parentNode.children[1].classList.remove("captured--opponent"); }); - }, 'json').error(function(jqxhr, status, error) { + }, 'json').fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the map data."); console.log(loadPath); console.log(status); @@ -1786,7 +1764,7 @@ function setupInputListeners() { FB_CTF.data.COUNTRIES = data; var df = $.Deferred(); return df.resolve(FB_CTF.data.COUNTRIES); - }, 'json').error(function(jqxhr, status, error) { + }, 'json').fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the game data."); console.log(loadPath); console.log(status); @@ -1821,9 +1799,7 @@ function setupInputListeners() { // add the category $group.attr('data-category', data.category); // add the status - var completed_list = data.completed; - var data_status = (completed_list.indexOf(FB_CTF.data.CONF.currentTeam) >= 0) ? 'completed' : 'remaining'; - $group.attr('data-status', data_status); + $group.attr('data-status', 'remaining'); } }); } @@ -2072,7 +2048,7 @@ function setupInputListeners() { FB_CTF.data.COMMAND = data; var df = $.Deferred(); return df.resolve(FB_CTF.data.COMMAND); - }, 'json').error(function(jqxhr, status, error) { + }, 'json').fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the commands data."); console.log(loadPath); console.log(status); @@ -2549,7 +2525,7 @@ function setupInputListeners() { }); eventListeners(); } - }, 'json').error(function(jqxhr, status, error) { + }, 'json').fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the commands."); console.log(status); console.log(error); @@ -2574,12 +2550,12 @@ function setupInputListeners() { FB_CTF.init = function() { $body = $('body'); - $('#login_button').click(Index.loginTeam); + $('#login_button').on('click', Index.loginTeam); var names_required = $('input[name=action]').val() === 'register_names'; if (names_required) { - $('#register_button').click(Index.registerNames); + $('#register_button').on('click', Index.registerNames); } else { - $('#register_button').click(Index.registerTeam); + $('#register_button').on('click', Index.registerTeam); } // load the svg sprite. This is in the FB_CTF namespace @@ -2601,7 +2577,7 @@ function setupInputListeners() { // load the sliders Slider.init(5); - // load the grpahics + // load the graphics Graphics.init(FB_CTF.data); }).trigger('content-loaded'); @@ -2837,7 +2813,7 @@ function setupInputListeners() { $customEmblemInput.trigger('click'); }); // on file input change, set image preview and emblem carousel notice - $customEmblemInput.change(function() { + $customEmblemInput.on('change', function() { var input = this; if (input.files && input.files[0]) { if (input.files[0].size > (1000*1024)) { diff --git a/src/static/js/graphics.js b/src/static/js/graphics.js index 7b7ac9e6..25cef272 100644 --- a/src/static/js/graphics.js +++ b/src/static/js/graphics.js @@ -166,7 +166,7 @@ module.exports = { var xCoor = d3.mouse(this)[0]; d3.select('.mouseline').attr('transform', 'translate(' + xCoor + ',0)'); }); - }, 'json').error(function(jqxhr, status, error) { + }, 'json').fail(function(jqxhr, status, error) { console.error("There was a problem retrieving the game scores."); console.log(status); console.log(error); diff --git a/src/static/js/index.js b/src/static/js/index.js index ea1b5312..dcb16904 100644 --- a/src/static/js/index.js +++ b/src/static/js/index.js @@ -130,6 +130,9 @@ function sendIndexRequest(request_data) { if (responseData.message === 'Login failed') { teamLoginFormError(); } + if (responseData.message === 'Login closed') { + window.location.replace("/index.php?page=countdown"); + } if (responseData.message === 'Registration failed') { teamNameFormError(); teamTokenFormError();