diff --git a/sql/incoming-schema-changes.sql b/sql/incoming-schema-changes.sql index 1670a572..14cb8332 100644 --- a/sql/incoming-schema-changes.sql +++ b/sql/incoming-schema-changes.sql @@ -1,3 +1,110 @@ USE ifdb; -- use this script for pending changes to the production DB schema + + + +-- Add column for game search filter to the users table + +ALTER TABLE `users` ADD COLUMN `game_filter` VARCHAR(150) DEFAULT ''; + + + + + +-- Add a view to track the news items for each game. +-- "G" in the news table means the news is about a game, +-- and "A" means the news has not been deleted. +-- Do not include versions of news items that have been +-- superseded by later edits. + +CREATE VIEW `recentgamenews` AS + SELECT + newsid AS news_id, + sourceid AS game_id, + created AS news_create_date + FROM news + WHERE source = 'G' + AND status = 'A' + AND newsid NOT IN ( + SELECT supersedes + FROM news + WHERE supersedes IS NOT NULL + ) + ORDER BY news_id DESC; + + + +-- Create a materialized view to store the data from the recentgamenews view + +CREATE TABLE recentgamenews_mv ( + news_id BIGINT(20) unsigned NOT NULL, + game_id VARCHAR(32) NOT NULL, + news_create_date DATETIME NOT NULL, + PRIMARY KEY (news_id), + KEY (game_id) +); + + + +-- Populate the recentgamenews_mv materialized view from the recentgamenews view + +lock tables recentgamenews_mv write, recentgamenews read; +truncate table recentgamenews_mv; +insert into recentgamenews_mv select * from recentgamenews; +unlock tables; + + + +-- Procedure to update one row of the recentgamenews_mv materialized view + +DROP PROCEDURE IF EXISTS refresh_recentgamenews_mv; +DELIMITER $$ + +CREATE PROCEDURE refresh_recentgamenews_mv ( + IN new_newsid BIGINT(20) +) +BEGIN +select * +from recentgamenews +where news_id = new_newsid +into @news_id, + @game_id, + @news_create_date; +if @news_id is null then + delete from recentgamenews_mv where news_id = new_news_id; +else +insert into recentgamenews_mv +values ( + @news_id, + @game_id, + @news_create_date + ) on duplicate key +update news_id = @news_id, + game_id = @game_id, + news_create_date = @news_create_date; +END IF; +END; +$$ + +DELIMITER ; + + + +-- Create triggers so that when a news item for a game is added to the news table, +-- the latest news date and the latest news id for that game will automatically +-- be updated in the recentgamenews_mv materialized view. [Question: How do I limit this to just game news?] + +CREATE TRIGGER recentgamenews_insert +AFTER INSERT ON news FOR EACH ROW +call refresh_recentgamenews_mv(NEW.newsid); + + +CREATE TRIGGER recentgamenews_update +AFTER UPDATE ON news FOR EACH ROW +call refresh_recentgamenews_mv(NEW.newsid); + + +CREATE TRIGGER recentgamenews_delete +AFTER DELETE ON news FOR EACH ROW +call refresh_recentgamenews_mv(OLD.newsid); diff --git a/sql/patch-full-schema.sql b/sql/patch-full-schema.sql index 40fae266..ebf2e98a 100644 --- a/sql/patch-full-schema.sql +++ b/sql/patch-full-schema.sql @@ -1,2 +1,449 @@ USE ifdb; +ALTER TABLE `users` ADD COLUMN `game_filter` VARCHAR(150) DEFAULT ''; + +-- +-- Final view structure for view `gameRatingsSandbox0` +-- + +/*!50001 DROP TABLE IF EXISTS `gameRatingsSandbox0`*/; +/*!50001 DROP VIEW IF EXISTS `gameRatingsSandbox0`*/; +/*!50001 SET @saved_cs_client = @@character_set_client */; +/*!50001 SET @saved_cs_results = @@character_set_results */; +/*!50001 SET @saved_col_connection = @@collation_connection */; +/*!50001 SET character_set_client = utf8 */; +/*!50001 SET character_set_results = utf8 */; +/*!50001 SET collation_connection = utf8_general_ci */; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */ +/*!50001 VIEW `gameRatingsSandbox0` AS +select `averaged`.`gameid` AS `gameid`, + `averaged`.`rated1` AS `rated1`, + `averaged`.`rated2` AS `rated2`, + `averaged`.`rated3` AS `rated3`, + `averaged`.`rated4` AS `rated4`, + `averaged`.`rated5` AS `rated5`, + `averaged`.`numRatingsInAvg` AS `numRatingsInAvg`, + `averaged`.`numRatingsTotal` AS `numRatingsTotal`, + `averaged`.`numMemberReviews` AS `numMemberReviews`, + `averaged`.`lastReviewDate` AS `lastReviewDate`, + `averaged`.`avgRating` AS `avgRating`, + pow( + ( + pow(1 - `averaged`.`avgRating`, 2) * `averaged`.`rated1` + + pow(2 - `averaged`.`avgRating`, 2) * `averaged`.`rated2` + + pow(3 - `averaged`.`avgRating`, 2) * `averaged`.`rated3` + + pow(4 - `averaged`.`avgRating`, 2) * `averaged`.`rated4` + + pow(5 - `averaged`.`avgRating`, 2) * `averaged`.`rated5` + ) / `averaged`.`numRatingsInAvg`, + 0.5 + ) AS `stdDevRating`, +( + 5 * (`averaged`.`rated5` + 1) + + 4 * (`averaged`.`rated4` + 1) + + 3 * (`averaged`.`rated3` + 1) + + 2 * (`averaged`.`rated2` + 1) + + 1 * (`averaged`.`rated1` + 1) + ) / (5 + `averaged`.`numRatingsInAvg`) - 1.65 * sqrt( + ( + ( + 25 * (`averaged`.`rated5` + 1) + + 16 * (`averaged`.`rated4` + 1) + + 9 * (`averaged`.`rated3` + 1) + + 4 * (`averaged`.`rated2` + 1) + + 1 * (`averaged`.`rated1` + 1) + ) / (5 + `averaged`.`numRatingsInAvg`) - pow( + ( + 5 * (`averaged`.`rated5` + 1) + + 4 * (`averaged`.`rated4` + 1) + + 3 * (`averaged`.`rated3` + 1) + + 2 * (`averaged`.`rated2` + 1) + + 1 * (`averaged`.`rated1` + 1) + ) / (5 + `averaged`.`numRatingsInAvg`), + 2 + ) + ) / (6 + `averaged`.`numRatingsInAvg`) + ) AS `starsort` +from ( + select `rating_counts`.`gameid` AS `gameid`, + `rating_counts`.`rated1` AS `rated1`, + `rating_counts`.`rated2` AS `rated2`, + `rating_counts`.`rated3` AS `rated3`, + `rating_counts`.`rated4` AS `rated4`, + `rating_counts`.`rated5` AS `rated5`, + `rating_counts`.`numRatingsInAvg` AS `numRatingsInAvg`, + `rating_counts`.`numRatingsTotal` AS `numRatingsTotal`, + `rating_counts`.`numMemberReviews` AS `numMemberReviews`, + `rating_counts`.`lastReviewDate` AS `lastReviewDate`, +( + `rating_counts`.`rated1` + + `rating_counts`.`rated2` * 2 + + `rating_counts`.`rated3` * 3 + + `rating_counts`.`rated4` * 4 + + `rating_counts`.`rated5` * 5 + ) / `rating_counts`.`numRatingsInAvg` AS `avgRating` + from ( + select `grouped`.`gameid` AS `gameid`, + sum( + case + when `grouped`.`rating` = 1 + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `rated1`, + sum( + case + when `grouped`.`rating` = 2 + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `rated2`, + sum( + case + when `grouped`.`rating` = 3 + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `rated3`, + sum( + case + when `grouped`.`rating` = 4 + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `rated4`, + sum( + case + when `grouped`.`rating` = 5 + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `rated5`, + sum( + case + when `grouped`.`rating` in (1, 2, 3, 4, 5) + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `numRatingsInAvg`, + sum( + case + when `grouped`.`rating` in (1, 2, 3, 4, 5) then `grouped`.`count` + else 0 + end + ) AS `numRatingsTotal`, + sum( + case + when `grouped`.`hasReview` then `grouped`.`count` + else 0 + end + ) AS `numMemberReviews`, + max( + case + when `grouped`.`hasReview` then `grouped`.`lastRatingOrReviewDate` + else null + end + ) AS `lastReviewDate` + from ( + select count(`ifdb`.`reviews`.`id`) AS `count`, + `ifdb`.`reviews`.`rating` AS `rating`, + `ifdb`.`games`.`id` AS `gameid`, + ifnull(`ifdb`.`reviews`.`RFlags`, 0) & 2 AS `omitted`, + `ifdb`.`reviews`.`review` is not null AS `hasReview`, + max(ifnull(embargodate, createdate)) AS `lastRatingOrReviewDate` + from ( + `ifdb`.`games` + left outer join `ifdb`.`reviews` on ( + `ifdb`.`games`.`id` = `ifdb`.`reviews`.`gameid` + and ifnull( + current_timestamp() > `ifdb`.`reviews`.`embargodate`, + 1 + ) + and `ifdb`.`reviews`.`special` is null + and `ifdb`.`reviews`.`userid` not in (select `ifdb`.`users`.`id` from `ifdb`.`users` where `ifdb`.`users`.`Sandbox` = 1) + ) + ) + group by `ifdb`.`reviews`.`rating`, + `ifdb`.`games`.`id`, + ifnull(`ifdb`.`reviews`.`RFlags`, 0) & 2, + ifnull( + `ifdb`.`reviews`.`special`, + `ifdb`.`reviews`.`review` + ) is not null + ) `grouped` + group by `grouped`.`gameid` + ) `rating_counts` + ) `averaged` +*/; +/*!50001 SET character_set_client = @saved_cs_client */; +/*!50001 SET character_set_results = @saved_cs_results */; +/*!50001 SET collation_connection = @saved_col_connection */; + +-- +-- Final view structure for view `gameRatingsSandbox01` +-- + +/*!50001 DROP TABLE IF EXISTS `gameRatingsSandbox01`*/; +/*!50001 DROP VIEW IF EXISTS `gameRatingsSandbox01`*/; +/*!50001 SET @saved_cs_client = @@character_set_client */; +/*!50001 SET @saved_cs_results = @@character_set_results */; +/*!50001 SET @saved_col_connection = @@collation_connection */; +/*!50001 SET character_set_client = utf8 */; +/*!50001 SET character_set_results = utf8 */; +/*!50001 SET collation_connection = utf8_general_ci */; +/*!50001 CREATE ALGORITHM=UNDEFINED */ +/*!50013 DEFINER=`root`@`localhost` SQL SECURITY DEFINER */ +/*!50001 VIEW `gameRatingsSandbox01` AS +select `averaged`.`gameid` AS `gameid`, + `averaged`.`rated1` AS `rated1`, + `averaged`.`rated2` AS `rated2`, + `averaged`.`rated3` AS `rated3`, + `averaged`.`rated4` AS `rated4`, + `averaged`.`rated5` AS `rated5`, + `averaged`.`numRatingsInAvg` AS `numRatingsInAvg`, + `averaged`.`numRatingsTotal` AS `numRatingsTotal`, + `averaged`.`numMemberReviews` AS `numMemberReviews`, + `averaged`.`lastReviewDate` AS `lastReviewDate`, + `averaged`.`avgRating` AS `avgRating`, + pow( + ( + pow(1 - `averaged`.`avgRating`, 2) * `averaged`.`rated1` + + pow(2 - `averaged`.`avgRating`, 2) * `averaged`.`rated2` + + pow(3 - `averaged`.`avgRating`, 2) * `averaged`.`rated3` + + pow(4 - `averaged`.`avgRating`, 2) * `averaged`.`rated4` + + pow(5 - `averaged`.`avgRating`, 2) * `averaged`.`rated5` + ) / `averaged`.`numRatingsInAvg`, + 0.5 + ) AS `stdDevRating`, +( + 5 * (`averaged`.`rated5` + 1) + + 4 * (`averaged`.`rated4` + 1) + + 3 * (`averaged`.`rated3` + 1) + + 2 * (`averaged`.`rated2` + 1) + + 1 * (`averaged`.`rated1` + 1) + ) / (5 + `averaged`.`numRatingsInAvg`) - 1.65 * sqrt( + ( + ( + 25 * (`averaged`.`rated5` + 1) + + 16 * (`averaged`.`rated4` + 1) + + 9 * (`averaged`.`rated3` + 1) + + 4 * (`averaged`.`rated2` + 1) + + 1 * (`averaged`.`rated1` + 1) + ) / (5 + `averaged`.`numRatingsInAvg`) - pow( + ( + 5 * (`averaged`.`rated5` + 1) + + 4 * (`averaged`.`rated4` + 1) + + 3 * (`averaged`.`rated3` + 1) + + 2 * (`averaged`.`rated2` + 1) + + 1 * (`averaged`.`rated1` + 1) + ) / (5 + `averaged`.`numRatingsInAvg`), + 2 + ) + ) / (6 + `averaged`.`numRatingsInAvg`) + ) AS `starsort` +from ( + select `rating_counts`.`gameid` AS `gameid`, + `rating_counts`.`rated1` AS `rated1`, + `rating_counts`.`rated2` AS `rated2`, + `rating_counts`.`rated3` AS `rated3`, + `rating_counts`.`rated4` AS `rated4`, + `rating_counts`.`rated5` AS `rated5`, + `rating_counts`.`numRatingsInAvg` AS `numRatingsInAvg`, + `rating_counts`.`numRatingsTotal` AS `numRatingsTotal`, + `rating_counts`.`numMemberReviews` AS `numMemberReviews`, + `rating_counts`.`lastReviewDate` AS `lastReviewDate`, +( + `rating_counts`.`rated1` + + `rating_counts`.`rated2` * 2 + + `rating_counts`.`rated3` * 3 + + `rating_counts`.`rated4` * 4 + + `rating_counts`.`rated5` * 5 + ) / `rating_counts`.`numRatingsInAvg` AS `avgRating` + from ( + select `grouped`.`gameid` AS `gameid`, + sum( + case + when `grouped`.`rating` = 1 + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `rated1`, + sum( + case + when `grouped`.`rating` = 2 + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `rated2`, + sum( + case + when `grouped`.`rating` = 3 + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `rated3`, + sum( + case + when `grouped`.`rating` = 4 + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `rated4`, + sum( + case + when `grouped`.`rating` = 5 + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `rated5`, + sum( + case + when `grouped`.`rating` in (1, 2, 3, 4, 5) + and `grouped`.`omitted` = 0 then `grouped`.`count` + else 0 + end + ) AS `numRatingsInAvg`, + sum( + case + when `grouped`.`rating` in (1, 2, 3, 4, 5) then `grouped`.`count` + else 0 + end + ) AS `numRatingsTotal`, + sum( + case + when `grouped`.`hasReview` then `grouped`.`count` + else 0 + end + ) AS `numMemberReviews`, + max( + case + when `grouped`.`hasReview` then `grouped`.`lastRatingOrReviewDate` + else null + end + ) AS `lastReviewDate` + from ( + select count(`ifdb`.`reviews`.`id`) AS `count`, + `ifdb`.`reviews`.`rating` AS `rating`, + `ifdb`.`games`.`id` AS `gameid`, + ifnull(`ifdb`.`reviews`.`RFlags`, 0) & 2 AS `omitted`, + `ifdb`.`reviews`.`review` is not null AS `hasReview`, + max(ifnull(embargodate, createdate)) AS `lastRatingOrReviewDate` + from ( + `ifdb`.`games` + left outer join `ifdb`.`reviews` on ( + `ifdb`.`games`.`id` = `ifdb`.`reviews`.`gameid` + and ifnull( + current_timestamp() > `ifdb`.`reviews`.`embargodate`, + 1 + ) + and `ifdb`.`reviews`.`special` is null + ) + ) + group by `ifdb`.`reviews`.`rating`, + `ifdb`.`games`.`id`, + ifnull(`ifdb`.`reviews`.`RFlags`, 0) & 2, + ifnull( + `ifdb`.`reviews`.`special`, + `ifdb`.`reviews`.`review` + ) is not null + ) `grouped` + group by `grouped`.`gameid` + ) `rating_counts` + ) `averaged` +*/; +/*!50001 SET character_set_client = @saved_cs_client */; +/*!50001 SET character_set_results = @saved_cs_results */; +/*!50001 SET collation_connection = @saved_col_connection */; + +drop table if exists gameRatingsSandbox0_mv; +create table gameRatingsSandbox0_mv ( + `gameid` varchar(32) NOT NULL DEFAULT '', + `rated1` int unsigned, + `rated2` int unsigned, + `rated3` int unsigned, + `rated4` int unsigned, + `rated5` int unsigned, + `numRatingsInAvg` int unsigned, + `numRatingsTotal` int unsigned, + `numMemberReviews` int unsigned, + `lastReviewDate` datetime NOT NULL, + `avgRating` double, + `stdDevRating` double, + `starsort` double, + `updated` date, + PRIMARY KEY (`gameid`), + KEY `numRatingsInAvg` (`numRatingsInAvg`), + KEY `numRatingsTotal` (`numRatingsTotal`), + KEY `numMemberReviews` (`numMemberReviews`), + KEY `avgRating` (`avgRating`), + KEY `stdDevRating` (`stdDevRating`), + KEY `starsort` (`starsort`), + KEY `lastReviewDate` (`lastReviewDate`) +) ENGINE = MyISAM DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci; + +lock tables gameRatingsSandbox0_mv write, gameRatingsSandbox0 read; +truncate table gameRatingsSandbox0_mv; +insert into gameRatingsSandbox0_mv select *, now() from gameRatingsSandbox0; +unlock tables; + +DROP PROCEDURE IF EXISTS refresh_gameRatingsSandbox0_mv; +DELIMITER $$ + +CREATE PROCEDURE refresh_gameRatingsSandbox0_mv ( + IN new_gameid varchar(32) +) +BEGIN +select * +from gameRatingsSandbox0 +where gameid = new_gameid into @gameid, + @rated1, + @rated2, + @rated3, + @rated4, + @rated5, + @numRatingsInAvg, + @numRatingsTotal, + @numMemberReviews, + @lastReviewDate, + @avgRating, + @stdDevRating, + @starsort; +if @gameid is null then + delete from gameRatingsSandbox0_mv where gameid = new_gameid; +else +insert into gameRatingsSandbox0_mv +values ( + @gameid, + @rated1, + @rated2, + @rated3, + @rated4, + @rated5, + @numRatingsInAvg, + @numRatingsTotal, + @numMemberReviews, + @lastReviewDate, + @avgRating, + @stdDevRating, + @starsort, + now() + ) on duplicate key +update gameid = @gameid, + rated1 = @rated1, + rated2 = @rated2, + rated3 = @rated3, + rated4 = @rated4, + rated5 = @rated5, + numRatingsInAvg = @numRatingsInAvg, + numRatingsTotal = @numRatingsTotal, + numMemberReviews = @numMemberReviews, + lastReviewDate = @lastReviewDate, + avgRating = @avgRating, + stdDevRating = @stdDevRating, + starsort = @starsort, + updated = now(); +END IF; +END; +$$ + +DELIMITER ; diff --git a/sql/unscrub-ifarchive.sql b/sql/unscrub-ifarchive.sql index 2fe363e8..81b9244b 100644 --- a/sql/unscrub-ifarchive.sql +++ b/sql/unscrub-ifarchive.sql @@ -311,6 +311,7 @@ select `averaged`.`gameid` AS `gameid`, `averaged`.`numRatingsInAvg` AS `numRatingsInAvg`, `averaged`.`numRatingsTotal` AS `numRatingsTotal`, `averaged`.`numMemberReviews` AS `numMemberReviews`, + `averaged`.`lastReviewDate` AS `lastReviewDate`, `averaged`.`avgRating` AS `avgRating`, pow( ( @@ -358,6 +359,7 @@ from ( `rating_counts`.`numRatingsInAvg` AS `numRatingsInAvg`, `rating_counts`.`numRatingsTotal` AS `numRatingsTotal`, `rating_counts`.`numMemberReviews` AS `numMemberReviews`, + `rating_counts`.`lastReviewDate` AS `lastReviewDate`, ( `rating_counts`.`rated1` + `rating_counts`.`rated2` * 2 @@ -420,13 +422,20 @@ from ( when `grouped`.`hasReview` then `grouped`.`count` else 0 end - ) AS `numMemberReviews` + ) AS `numMemberReviews`, + max( + case + when `grouped`.`hasReview` then `grouped`.`lastRatingOrReviewDate` + else null + end + ) AS `lastReviewDate` from ( select count(`ifdb`.`reviews`.`id`) AS `count`, `ifdb`.`reviews`.`rating` AS `rating`, `ifdb`.`games`.`id` AS `gameid`, ifnull(`ifdb`.`reviews`.`RFlags`, 0) & 2 AS `omitted`, - `ifdb`.`reviews`.`review` is not null AS `hasReview` + `ifdb`.`reviews`.`review` is not null AS `hasReview`, + max(ifnull(embargodate, createdate)) AS `lastRatingOrReviewDate` from ( `ifdb`.`games` left outer join `ifdb`.`reviews` on ( @@ -479,6 +488,7 @@ select `averaged`.`gameid` AS `gameid`, `averaged`.`numRatingsInAvg` AS `numRatingsInAvg`, `averaged`.`numRatingsTotal` AS `numRatingsTotal`, `averaged`.`numMemberReviews` AS `numMemberReviews`, + `averaged`.`lastReviewDate` AS `lastReviewDate`, `averaged`.`avgRating` AS `avgRating`, pow( ( @@ -526,6 +536,7 @@ from ( `rating_counts`.`numRatingsInAvg` AS `numRatingsInAvg`, `rating_counts`.`numRatingsTotal` AS `numRatingsTotal`, `rating_counts`.`numMemberReviews` AS `numMemberReviews`, + `rating_counts`.`lastReviewDate` AS `lastReviewDate`, ( `rating_counts`.`rated1` + `rating_counts`.`rated2` * 2 @@ -588,13 +599,20 @@ from ( when `grouped`.`hasReview` then `grouped`.`count` else 0 end - ) AS `numMemberReviews` + ) AS `numMemberReviews`, + max( + case + when `grouped`.`hasReview` then `grouped`.`lastRatingOrReviewDate` + else null + end + ) AS `lastReviewDate` from ( select count(`ifdb`.`reviews`.`id`) AS `count`, `ifdb`.`reviews`.`rating` AS `rating`, `ifdb`.`games`.`id` AS `gameid`, ifnull(`ifdb`.`reviews`.`RFlags`, 0) & 2 AS `omitted`, - `ifdb`.`reviews`.`review` is not null AS `hasReview` + `ifdb`.`reviews`.`review` is not null AS `hasReview`, + max(ifnull(embargodate, createdate)) AS `lastRatingOrReviewDate` from ( `ifdb`.`games` left outer join `ifdb`.`reviews` on ( @@ -874,6 +892,7 @@ create table gameRatingsSandbox0_mv ( `numRatingsInAvg` int unsigned, `numRatingsTotal` int unsigned, `numMemberReviews` int unsigned, + `lastReviewDate` datetime NOT NULL, `avgRating` double, `stdDevRating` double, `starsort` double, @@ -884,7 +903,8 @@ create table gameRatingsSandbox0_mv ( KEY `numMemberReviews` (`numMemberReviews`), KEY `avgRating` (`avgRating`), KEY `stdDevRating` (`stdDevRating`), - KEY `starsort` (`starsort`) + KEY `starsort` (`starsort`), + KEY `lastReviewDate` (`lastReviewDate`) ) ENGINE = MyISAM DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci; lock tables gameRatingsSandbox0_mv write, gameRatingsSandbox0 read; @@ -910,6 +930,7 @@ where gameid = new_gameid into @gameid, @numRatingsInAvg, @numRatingsTotal, @numMemberReviews, + @lastReviewDate, @avgRating, @stdDevRating, @starsort; @@ -927,6 +948,7 @@ values ( @numRatingsInAvg, @numRatingsTotal, @numMemberReviews, + @lastReviewDate, @avgRating, @stdDevRating, @starsort, @@ -941,6 +963,7 @@ update gameid = @gameid, numRatingsInAvg = @numRatingsInAvg, numRatingsTotal = @numRatingsTotal, numMemberReviews = @numMemberReviews, + lastReviewDate = @lastReviewDate, avgRating = @avgRating, stdDevRating = @stdDevRating, starsort = @starsort, diff --git a/www/allnew b/www/allnew index 10b47e0d..25593971 100644 --- a/www/allnew +++ b/www/allnew @@ -17,13 +17,14 @@ if ($pg < 1) $pg = 1; $showFlagged = isset($_GET['showFlagged']) && $_GET['showFlagged']; +$override_game_filter = get_req_data('nogamefilter'); // calculate where that puts us in the results $firstOnPage = ($pg - 1) * PER_PAGE; $lastOnPage = $firstOnPage + PER_PAGE - 1; // query the items -$items = getNewItems($db, $lastOnPage + 1, $type); +list($items, $game_filter_was_applied) = getNewItems($db, $lastOnPage + 1, $type, $override_game_filter); $tot = count($items); $params = []; @@ -31,8 +32,12 @@ if ($showFlagged) $params['showFlagged'] = 1; if ($reviews) $params['reviews'] = ""; // set up the page controls +$game_filter_parameter = ""; +if ($override_game_filter) { + $game_filter_parameter = "&nogamefilter=1"; +} $pageCtl = "" - . makePageControl("allnew?" . http_build_query($params), $pg, $pg + ($tot > PER_PAGE ? 1 : 0), + . makePageControl("allnew?" . http_build_query($params) . $game_filter_parameter, $pg, $pg + ($tot > PER_PAGE ? 1 : 0), $firstOnPage, $lastOnPage, -1, false, false, false) . ""; @@ -53,6 +58,11 @@ showNewItems($db, $firstOnPage, $lastOnPage, $items, ['showFlagged' => $showFlag echo "
$pageCtl
\n";
echo ""; // prerender-moderate
+if ($game_filter_was_applied) {
+ $games_filtered_announcement = writeGamesFilteredAnnouncement("all_new_reviews", null, null);
+ echo "
" . $games_filtered_announcement . "
"; +} + // end the page pageFooter(); diff --git a/www/components/competitions.php b/www/components/competitions.php index 7b8ae1fe..f9e11767 100644 --- a/www/components/competitions.php +++ b/www/components/competitions.php @@ -9,7 +9,7 @@ Browse competitions | Search competitions -
\ No newline at end of file + diff --git a/www/components/games.php b/www/components/games.php index fd3d1ae2..330f85ce 100644 --- a/www/components/games.php +++ b/www/components/games.php @@ -17,7 +17,7 @@ define("ENABLE_IMAGES", 1); // get the latest games and game news -$items = getNewItems($db, 6, NEWITEMS_GAMES | NEWITEMS_GAMENEWS); +list($items, $game_filter_was_applied) = getNewItems($db, 6, NEWITEMS_GAMES | NEWITEMS_GAMENEWS); // show the items $totcnt = count($items); diff --git a/www/components/ifdb-recommends.php b/www/components/ifdb-recommends.php index 5350728f..a17232a9 100644 --- a/www/components/ifdb-recommends.php +++ b/www/components/ifdb-recommends.php @@ -22,12 +22,13 @@ function sortBySortorder($a, $b) $limit = "limit 0, $maxpicks"; $browse = 1; $count_all_possible_rows = false; +$override_game_filter = 0; // run the search for highly-rated games list($recs, $rowcnt, $sortList, $errMsg, $summaryDesc, $badges, - $specials, $specialsUsed, $orderBy) = - doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_possible_rows); + $specials, $specialsUsed, $orderBy, $games_were_filtered) = + doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_possible_rows, $override_game_filter); $recs = array_values(array_filter($recs, function($r) { $buried = $r['flags'] & FLAG_SHOULD_HIDE; diff --git a/www/components/recommended-lists.php b/www/components/recommended-lists.php index 9ea9e703..15acbf7c 100644 --- a/www/components/recommended-lists.php +++ b/www/components/recommended-lists.php @@ -8,7 +8,7 @@ Browse lists | Search lists - \ No newline at end of file + diff --git a/www/components/reviews.php b/www/components/reviews.php index 89c591fd..03f70baf 100644 --- a/www/components/reviews.php +++ b/www/components/reviews.php @@ -1,7 +1,7 @@To see certain kinds of games less often,
+ you can create a filter using IFDB's
+ search prefixes. For
+ instance, to hide games in a certain language, games in a
+ certain genre, and games with a certain tag, you can type
+
-language:example -genre:example -tag:example
+ (replacing "example" with the name of the language, genre, or
+ tag). While you are logged in, your saved filter
+ will be used to hide games, but only on certain pages: the home page,
+ the "New Reviews on IFDB" page, and the search/browse page
+ (where the filter will automatically be added to the end of your
+ search terms). The "New Reviews on IFDB" page and the search/browse
+ page will show an option to temporarily turn off the filter.
Game information on IFDB is incomplete + and can have mistakes, so a filter is not a reliable + way to make sure that games are kid-friendly. + +
+ + +
' . $games_filtered_announcement . '
'; + } + if ($searchType == "game") { echo "' . $games_filtered_announcement . '
'; + } } diff --git a/www/searchutil.php b/www/searchutil.php index 1dcd988d..c10bef0a 100644 --- a/www/searchutil.php +++ b/www/searchutil.php @@ -43,7 +43,21 @@ function convertTimeStringToMinutes($h_m_string) { } -function doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_possible_rows = false) +// Construct a message telling the user that the game results were filtered +function writeGamesFilteredAnnouncement($page, $sort_order, $search_term) { + $games_filtered_announcement = 'Your account is set up to use a game filter by default, and that filter was applied on this page. You can '; + if ($page == "search_games") { + $games_filtered_announcement .= 'search again without the filter.'; + } else if ($page == "browse_games") { + $games_filtered_announcement .= 'also browse without the filter.'; + } else if ($page == "all_new_reviews") { + $games_filtered_announcement .= 'also browse without the filter.'; + } + return $games_filtered_announcement; +} + + +function doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_possible_rows = false, $override_game_filter = 0) { // we need the current user for some types of queries checkPersistentLogin(); @@ -73,6 +87,9 @@ function doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_ // assume no badge info $badges = false; + // So far, we haven't applied a custom game filter + $games_were_filtered = false; + // set up the parameters for the type of search we're performing if ($searchType == "list") { @@ -277,6 +294,7 @@ function doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_ stdDevRating as ratingdev, numRatingsTotal, numMemberReviews, + lastReviewDate, starsort, games.sort_title as sort_title, games.sort_author as sort_author, @@ -291,7 +309,21 @@ function doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_ $matchCols = "title, author, `desc`, tags"; $likeCol = "title"; $summaryDesc = "Games"; - } + + + // Handle custom game filters + if ($curuser && $override_game_filter != 1) { + // We're logged in, and haven't been told to override a custom game filter, so check for one + $result = mysqli_execute_query($db, "select game_filter from users where id = ?", [$curuser]); + if (!$result) throw new Exception("Error: " . mysqli_error($db)); + [$gameFilter] = mysql_fetch_row($result); + if ($gameFilter) { + // We've found a custom game filter, so add it to the end of the search term + $games_were_filtered = true; + $term .= " $gameFilter"; + } + } + } // parse the search for ($ofs = 0, $len = strlen($term), $words = array(), @@ -881,6 +913,8 @@ function doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_ 'old' => array('sort_pub,', 'Earliest Publication First'), 'long' => array('rounded_median_time_in_minutes desc, starsort desc,', 'Longest First'), 'short' => array('-rounded_median_time_in_minutes desc, starsort desc,', 'Shortest First'), + 'recently_reviewed' => array('lastReviewDate desc,', 'Recently Reviewed First'), + 'recent_game_news' => array('news_id desc,', 'Recent News First'), 'rand' => array('rand(),', 'Random Order')); if (count($words)) { $defSortBy = 'rel'; @@ -1002,6 +1036,15 @@ function doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_ } } + // If we're sorting by recent game news, select the news item's create date + // and join the recent game news + if ($searchType == "game" && $sortby == "recent_game_news") { + $selectList .= ", news_create_date"; + $tableList .= " left outer join recentgamenews_mv on games.id = recentgamenews_mv.game_id"; + } + + + // Build tags join $tagsJoin = ""; @@ -1065,20 +1108,17 @@ function doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_ } $sql_calc_found_rows = "sql_calc_found_rows"; - if ($searchType === "game" && !$term) { - // `sql_calc_found_rows` forces the query to ignore the `limit` clause in order to count all possible results. - // But when browsing for all games, we can do a fast `count(*)` query instead - $sql_calc_found_rows = ""; - } - if (!$count_all_possible_rows) { - // `sql_calc_found_rows` forces the query to ignore the `limit` clause - // in order to count all possible results, which means a slower full - // table scan. If the total number of rows is not needed, we can skip - // `sql_calc_found_rows` to speed up the query. + + if (($searchType === "game" && !$term) || !$count_all_possible_rows) { + // `sql_calc_found_rows` forces the query to ignore the `limit` clause in order to + // count all possible results, which means a full table scan, which can be slow. + // But if we're browsing all games, we can skip `sql_calc_found_rows` and do a fast + // `count(*)` query instead. If we're searching but we don't need the number of + // possible rows, we can skip the counting altogether. + $sql_calc_found_rows = ""; } - // build the SELECT statement $sql = "select $sql_calc_found_rows $selectList @@ -1147,7 +1187,7 @@ function doSearch($db, $term, $searchType, $sortby, $limit, $browse, $count_all_ // return the results return array($rows, $rowcnt, $sortList, $errMsg, $summaryDesc, - $badges, $specials, $specialsUsed, $orderBy); + $badges, $specials, $specialsUsed, $orderBy, $games_were_filtered); } ?>