diff --git a/sql/cambios.sql b/sql/cambios.sql index cc62f211..60de10b4 100644 --- a/sql/cambios.sql +++ b/sql/cambios.sql @@ -13565,4 +13565,59 @@ SELECT tml_pubs.PubCod, SELECT MAX(PstCod) AS NewestPstCod FROM for_posts GROUP BY ThrCod ORDER BY NewestPstCod DESC LIMIT 10; SELECT PstCod FROM for_posts ORDER BY PstCod DESC LIMIT 1; + + +------------------------------------------------------------------------------- +******************************************************************************* + +2021-11-25: Error en juegos + +mch_results.Score se ha guardado erróneamente en los juegos realizados aproximadamente entre estas fechas: +mch_result.StartTime>=20211124210000 AND mch_result.StartTime<=20211125160000 + +Sólo los que han contestado alguna pregunta: +mch_result.NumQstsNotBlank>0 + +La función: +void MchPrn_ComputeScoreAndUpdateMyMatchPrintInDB (long MchCod) +calcula Score y lo guarda en la base de datos. +Llama a: + Mch_GetMatchQuestionsFromDB (&Print); + MchPrn_ComputeScore (&Print); + TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question); + TstPrn_GetCorrectAndComputeChoAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, + struct Qst_Question *Question); + Qst_GetCorrectChoAnswerFromDB (Question); // <----- Aquí estaba el fallo + SELECT Correct + FROM tst_answers + WHERE QstCod=%ld // Question code + ORDER BY AnsInd; + TstPrn_ComputeChoAnsScore (PrintedQuestion,Question); + Print->Score += Print->PrintedQuestions[NumQst].Score; + MchPrn_UpdateMatchPrintInDB (&Print); + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/swad_action.c b/swad_action.c index 1d1cb579..cd5bd8c5 100644 --- a/swad_action.c +++ b/swad_action.c @@ -253,7 +253,9 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] = [ActChgPlgIP ] = { 780,-1,TabUnk,ActLstPlg , 0, 0, 0, 0, 0, 0,0x200,Act_CONT_NORM,Act_BRW_1ST_TAB,Plg_ChangePlgIP ,Plg_ContEditAfterChgPlg ,NULL}, [ActSetUp ] = { 840, 5,TabUnk,ActMtn , 0, 0, 0, 0, 0, 0,0x200,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Mtn_SetUp ,NULL}, - [ActReqRemOldCrs ] = {1109,-1,TabUnk,ActMtn , 0, 0, 0, 0, 0, 0,0x200,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Mtn_RemoveOldCrss ,NULL}, + [ActFixMchSco ] = {1915,-1,TabUnk,ActMtn , 0, 0, 0, 0, 0, 0,0x200,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,MchPrn_FixMatchesPrintsScores ,NULL}, + [ActFixTstSco ] = {1916,-1,TabUnk,ActMtn , 0, 0, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstPrn_FixTestsPrintsScores ,NULL}, + [ActReqRemOldCrs ] = {1109,-1,TabUnk,ActMtn , 0, 0, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Mtn_RemoveOldCrss ,NULL}, [ActRemOldCrs ] = {1110,-1,TabUnk,ActMtn , 0, 0, 0, 0, 0, 0,0x200,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Crs_RemoveOldCrss ,NULL}, // TabCty ****************************************************************** @@ -3739,6 +3741,8 @@ Act_Action_t Act_FromActCodToAction[1 + Act_MAX_ACTION_COD] = // Do not reuse un ActLstOneGam, // #1912 ActEdiMch, // #1913 ActChgMch, // #1914 + ActFixMchSco, // #1915 + ActFixTstSco, // #1916 }; /*****************************************************************************/ diff --git a/swad_action.h b/swad_action.h index 09c622f4..2a7e44c1 100644 --- a/swad_action.h +++ b/swad_action.h @@ -65,7 +65,7 @@ typedef enum typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to indicate obsolete action -#define Act_MAX_ACTION_COD 1914 +#define Act_MAX_ACTION_COD 1916 #define Act_MAX_OPTIONS_IN_MENU_PER_TAB 13 @@ -212,8 +212,10 @@ typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to #define ActChgPlgIP (ActRenMaiFul + 38) #define ActSetUp (ActRenMaiFul + 39) -#define ActReqRemOldCrs (ActRenMaiFul + 40) -#define ActRemOldCrs (ActRenMaiFul + 41) +#define ActFixMchSco (ActRenMaiFul + 40) +#define ActFixTstSco (ActRenMaiFul + 41) +#define ActReqRemOldCrs (ActRenMaiFul + 42) +#define ActRemOldCrs (ActRenMaiFul + 43) /*****************************************************************************/ /******************************** Country tab ********************************/ diff --git a/swad_changelog.h b/swad_changelog.h index 327b6573..ca41e058 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -602,14 +602,15 @@ TODO: FIX BUG, URGENT! En las fechas como par TODO: En las encuestas, que los estudiantes no puedan ver los resultados hasta que no finalice el plazo. */ -#define Log_PLATFORM_VERSION "SWAD 21.62.3 (2021-11-25)" +#define Log_PLATFORM_VERSION "SWAD 21.63 (2021-11-26)" #define CSS_FILE "swad21.59.css" #define JS_FILE "swad21.59.js" /* TODO: Rename CENTRE to CENTER in help wiki. TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams - Version 21.62.3: Nov 25, 2021 Fixed bug in test questions. Reported by Javier Fernández Baldomero and others. (319438 lines) + Version 21.63: Nov 26, 2021 Fixing of corruption in test prints and match prints. (320010 lines) + Version 21.62.3: Nov 25, 2021 Fixed bug in test questions. Reported by Javier Fernández Baldomero and Jesús González Peñalver. (319438 lines) Version 21.62.2: Nov 24, 2021 Fixed bug in forums. Reported by Javier Fernández Baldomero. (319422 lines) Version 21.62.1: Nov 24, 2021 Added some header files. (319422 lines) Version 21.62: Nov 24, 2021 Code refactoring in photos. (319415 lines) diff --git a/swad_maintenance.c b/swad_maintenance.c index dd17def8..e44f511c 100644 --- a/swad_maintenance.c +++ b/swad_maintenance.c @@ -27,6 +27,7 @@ #include "swad_course.h" #include "swad_database.h" +#include "swad_match_print.h" #include "swad_menu.h" /*****************************************************************************/ @@ -43,8 +44,10 @@ void Mtn_Maintenance (void) { /***** Contextual menu *****/ Mnu_ContextMenuBegin (); - Mtn_PutLinkToSetUp (); // Set up - Crs_PutLinkToRemoveOldCrss (); // Remove old courses + Mtn_PutLinkToSetUp (); // Set up + // MchPrn_PutLinkToFixMatchesPrintsScores (); // Fix match prints scores + // TstPrn_PutLinkToFixTestsPrintsScores (); // Fix test prints scores + Crs_PutLinkToRemoveOldCrss (); // Remove old courses Mnu_ContextMenuEnd (); } diff --git a/swad_match.c b/swad_match.c index c08303d9..5ca843df 100644 --- a/swad_match.c +++ b/swad_match.c @@ -106,12 +106,9 @@ static bool Mch_CheckIfVisibilityOfResultsCanBeChanged (const struct Mch_Match * static void Mch_ListOneOrMoreMatchesIcons (struct Gam_Games *Games, const struct Mch_Match *Match, const char *Anchor); -static void Mch_ListOneOrMoreMatchesAuthor (const struct Mch_Match *Match); -static void Mch_ListOneOrMoreMatchesTimes (const struct Mch_Match *Match,unsigned UniqueId); static void Mch_ListOneOrMoreMatchesTitleGrps (const struct Mch_Match *Match, const char *Anchor); static void Mch_GetAndWriteNamesOfGrpsAssociatedToMatch (const struct Mch_Match *Match); -static void Mch_ListOneOrMoreMatchesNumPlayers (const struct Mch_Match *Match); static void Mch_ListOneOrMoreMatchesStatus (struct Mch_Match *Match,unsigned NumQsts); static void Mch_ListOneOrMoreMatchesResult (struct Gam_Games *Games, const struct Mch_Match *Match); @@ -587,7 +584,7 @@ static void Mch_ListOneOrMoreMatchesIcons (struct Gam_Games *Games, /************* Put a column for teacher who created the match ****************/ /*****************************************************************************/ -static void Mch_ListOneOrMoreMatchesAuthor (const struct Mch_Match *Match) +void Mch_ListOneOrMoreMatchesAuthor (const struct Mch_Match *Match) { /***** Match author (teacher) *****/ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); @@ -599,7 +596,7 @@ static void Mch_ListOneOrMoreMatchesAuthor (const struct Mch_Match *Match) /***************** Put a column for match start and end times ****************/ /*****************************************************************************/ -static void Mch_ListOneOrMoreMatchesTimes (const struct Mch_Match *Match,unsigned UniqueId) +void Mch_ListOneOrMoreMatchesTimes (const struct Mch_Match *Match,unsigned UniqueId) { Dat_StartEndTime_t StartEndTime; char *Id; @@ -718,7 +715,7 @@ static void Mch_GetAndWriteNamesOfGrpsAssociatedToMatch (const struct Mch_Match /******************* Put a column for number of players **********************/ /*****************************************************************************/ -static void Mch_ListOneOrMoreMatchesNumPlayers (const struct Mch_Match *Match) +void Mch_ListOneOrMoreMatchesNumPlayers (const struct Mch_Match *Match) { /***** Number of players who have answered any question in the match ******/ HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); @@ -3728,35 +3725,6 @@ void Mch_GetMatchQuestionsFromDB (struct MchPrn_Print *Print) DB_FreeMySQLResult (&mysql_res); } -/*****************************************************************************/ -/******************** Compute match score for a student **********************/ -/*****************************************************************************/ - -void Mch_ComputeScore (struct MchPrn_Print *Print) - { - unsigned NumQst; - struct Qst_Question Question; - - for (NumQst = 0, Print->Score = 0.0; - NumQst < Print->NumQsts.All; - NumQst++) - { - /***** Create test question *****/ - Qst_QstConstructor (&Question); - Question.QstCod = Print->PrintedQuestions[NumQst].QstCod; - Question.Answer.Type = Qst_ANS_UNIQUE_CHOICE; - - /***** Compute score for this answer ******/ - TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question); - - /***** Update total score *****/ - Print->Score += Print->PrintedQuestions[NumQst].Score; - - /***** Destroy test question *****/ - Qst_QstDestructor (&Question); - } - } - /*****************************************************************************/ /***************** Draw a bar with the percentage of answers *****************/ /*****************************************************************************/ diff --git a/swad_match.h b/swad_match.h index c909627c..bd7d5892 100644 --- a/swad_match.h +++ b/swad_match.h @@ -98,6 +98,9 @@ void Mch_ListMatches (struct Gam_Games *Games, struct Gam_Game *Game, bool PutFormNewMatch); void Mch_GetDataOfMatchByCod (struct Mch_Match *Match); +void Mch_ListOneOrMoreMatchesAuthor (const struct Mch_Match *Match); +void Mch_ListOneOrMoreMatchesTimes (const struct Mch_Match *Match,unsigned UniqueId); +void Mch_ListOneOrMoreMatchesNumPlayers (const struct Mch_Match *Match); void Mch_ToggleVisResultsMchUsr (void); @@ -150,8 +153,6 @@ void Mch_StoreQuestionAnswer (const struct Mch_Match *Match,unsigned QstInd, void Mch_GetMatchQuestionsFromDB (struct MchPrn_Print *Print); -void Mch_ComputeScore (struct MchPrn_Print *Print); - void Mch_DrawBarNumUsrs (unsigned NumRespondersAns,unsigned NumRespondersQst,bool Correct); #endif diff --git a/swad_match_database.c b/swad_match_database.c index d8db406d..e4c74326 100644 --- a/swad_match_database.c +++ b/swad_match_database.c @@ -297,6 +297,31 @@ unsigned Mch_DB_GetAvailableMatchesInGame (MYSQL_RES **mysql_res,long GamCod) Gbl.Usrs.Me.UsrDat.UsrCod); } +/*****************************************************************************/ +/************************* Get matches between dates *************************/ +/*****************************************************************************/ + +unsigned Mch_DB_GetMatchesBetweenDates (MYSQL_RES **mysql_res, + const char *From, + const char *To) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get matches", + "SELECT GamCod," // row[ 0] + "MchCod," // row[ 1] + "UsrCod," // row[ 2] + "UNIX_TIMESTAMP(StartTime)," // row[ 3] + "UNIX_TIMESTAMP(EndTime)," // row[ 4] + "Title" // row[ 5] + " FROM mch_matches" + " WHERE StartTime>='%s'" + " AND StartTime<='%s'" + " ORDER BY GamCod," + "MchCod", + From, + To); + } + /*****************************************************************************/ /****************** Get parameter with what is being shown *******************/ /*****************************************************************************/ @@ -974,6 +999,34 @@ void Mch_DB_UpdateMatchPrint (const struct MchPrn_Print *Print) Str_SetDecimalPointToLocal (); // Return to local system } +/*****************************************************************************/ +/************************* Update match print score **************************/ +/*****************************************************************************/ + +void Mch_DB_UpdateMatchPrintScore (const struct MchPrn_Print *Print) + { + Str_SetDecimalPointToUS (); // To print the floating point as a dot +/* + DB_QueryUPDATE ("can not update match print", + "UPDATE mch_results" + " SET Score='%.15lg'" + " WHERE MchCod=%ld" + " AND UsrCod=%ld", + Print->Score, + Print->MchCod, + Print->UsrCod); +*/ + HTM_TxtF ("UPDATE mch_results" + " SET Score='%.15lg'" + " WHERE MchCod=%ld" + " AND UsrCod=%ld", + Print->Score, + Print->MchCod, + Print->UsrCod); + + Str_SetDecimalPointToLocal (); // Return to local system + } + /*****************************************************************************/ /*********************** Check if match print exists *************************/ /*****************************************************************************/ @@ -1018,6 +1071,23 @@ unsigned Mch_DB_GetMatchPrintData (MYSQL_RES **mysql_res, Gbl.Hierarchy.Crs.CrsCod); } +/*****************************************************************************/ +/********* Get data of a match print using match code and user code **********/ +/*****************************************************************************/ + +unsigned Mch_DB_GetPrintsInMatch (MYSQL_RES **mysql_res,long MchCod) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get match prints", + "SELECT UsrCod," // row[0] + "NumQsts," // row[1] + "NumQstsNotBlank," // row[2] + "Score" // row[3] + " FROM mch_results" + " WHERE MchCod=%ld", + MchCod); + } + /*****************************************************************************/ /************ Get number of users who have played a given match **************/ /*****************************************************************************/ diff --git a/swad_match_database.h b/swad_match_database.h index 5096d445..d1a1744e 100644 --- a/swad_match_database.h +++ b/swad_match_database.h @@ -44,6 +44,9 @@ unsigned Mch_DB_GetDataOfMatchByCod (MYSQL_RES **mysql_res,long MchCod); unsigned Mch_DB_GetStartEndMatchesInGame (MYSQL_RES **mysql_res,long GamCod); unsigned Mch_DB_GetMatchesInGame (MYSQL_RES **mysql_res,long GamCod); unsigned Mch_DB_GetAvailableMatchesInGame (MYSQL_RES **mysql_res,long GamCod); +unsigned Mch_DB_GetMatchesBetweenDates (MYSQL_RES **mysql_res, + const char *From, + const char *To); Mch_Showing_t Mch_DB_GetShowingFromStr (const char *Str); unsigned Mch_DB_GetNumMchsInGame (long GamCod); unsigned Mch_DB_GetNumUnfinishedMchsInGame (long GamCod); @@ -110,10 +113,12 @@ unsigned Mch_DB_GetElapsedTimeInMatch (MYSQL_RES **mysql_res,long MchCod); //----------------------------- Match results --------------------------------- void Mch_DB_CreateMatchPrint (const struct MchPrn_Print *Print); void Mch_DB_UpdateMatchPrint (const struct MchPrn_Print *Print); +void Mch_DB_UpdateMatchPrintScore (const struct MchPrn_Print *Print); bool Mch_DB_CheckIfMatchPrintExists (const struct MchPrn_Print *Print); unsigned Mch_DB_GetMatchPrintData (MYSQL_RES **mysql_res, const struct MchPrn_Print *Print); +unsigned Mch_DB_GetPrintsInMatch (MYSQL_RES **mysql_res,long MchCod); unsigned Mch_DB_GetNumUsrsWhoHavePlayedMch (long MchCod); unsigned Mch_DB_GetUsrsWhoHavePlayedMch (MYSQL_RES **mysql_res,long MchCod); unsigned Mch_DB_GetUsrsWhoHavePlayedGam (MYSQL_RES **mysql_res,long GamCod); diff --git a/swad_match_print.c b/swad_match_print.c index a6826b7e..b95ef8a2 100644 --- a/swad_match_print.c +++ b/swad_match_print.c @@ -25,8 +25,11 @@ /********************************* Headers ***********************************/ /*****************************************************************************/ +#include // For fabs + #include "swad_database.h" #include "swad_date.h" +#include "swad_error.h" #include "swad_global.h" #include "swad_match.h" #include "swad_match_database.h" @@ -42,8 +45,11 @@ extern struct Globals Gbl; /***************************** Private prototypes ****************************/ /*****************************************************************************/ +static void MchPrn_ComputeScore (struct MchPrn_Print *Print); static void MchPrn_UpdateMatchPrintInDB (const struct MchPrn_Print *Print); +static void MchPrn_ListPrintsToFix (long MchCod); + /*****************************************************************************/ /**************************** Reset match print ******************************/ /*****************************************************************************/ @@ -72,12 +78,41 @@ void MchPrn_ComputeScoreAndUpdateMyMatchPrintInDB (long MchCod) Print.MchCod = MchCod; Print.UsrCod = Gbl.Usrs.Me.UsrDat.UsrCod; Mch_GetMatchQuestionsFromDB (&Print); - Mch_ComputeScore (&Print); + MchPrn_ComputeScore (&Print); /***** Update my match result in database *****/ MchPrn_UpdateMatchPrintInDB (&Print); } +/*****************************************************************************/ +/***************** Compute match print score for a student *******************/ +/*****************************************************************************/ + +static void MchPrn_ComputeScore (struct MchPrn_Print *Print) + { + unsigned NumQst; + struct Qst_Question Question; + + for (NumQst = 0, Print->Score = 0.0; + NumQst < Print->NumQsts.All; + NumQst++) + { + /***** Create test question *****/ + Qst_QstConstructor (&Question); + Question.QstCod = Print->PrintedQuestions[NumQst].QstCod; + Question.Answer.Type = Qst_ANS_UNIQUE_CHOICE; + + /***** Compute score for this answer ******/ + TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question); + + /***** Update total score *****/ + Print->Score += Print->PrintedQuestions[NumQst].Score; + + /***** Destroy test question *****/ + Qst_QstDestructor (&Question); + } + } + /*****************************************************************************/ /************************* Create/update match print *************************/ /*****************************************************************************/ @@ -133,3 +168,232 @@ void MchPrn_GetMatchPrintDataByMchCodAndUsrCod (struct MchPrn_Print *Print) /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); } + +/*****************************************************************************/ +/******** Recompute scores stored in match prints made on 2021-11-25 *********/ +/*****************************************************************************/ + +void MchPrn_PutLinkToFixMatchesPrintsScores (void) + { + Lay_PutContextualLinkIconText (ActFixMchSco,NULL, + NULL,NULL, + "recycle.svg", + "Recalcular puntuación partidas"); + } + +void MchPrn_FixMatchesPrintsScores (void) + { + extern const char *Txt_Matches; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumMatches; + unsigned NumMatch; + unsigned UniqueId; + struct Mch_Match Match; + Dat_StartEndTime_t StartEndTime; + + /***** Reset match *****/ + Mch_ResetMatch (&Match); + + Box_BoxBegin ("100%",Txt_Matches, + NULL,NULL, + NULL,Box_NOT_CLOSABLE); + + /***** Get data of matches from database *****/ + NumMatches = Mch_DB_GetMatchesBetweenDates (&mysql_res, + "2021-11-24 20:00:00", // From + "2021-11-25 16:00:00"); // To + + /***** Begin table *****/ + HTM_TABLE_BeginWidePadding (2); + + /***** Write rows *****/ + for (NumMatch = 0, UniqueId = 1; + NumMatch < NumMatches; + NumMatch++, UniqueId++) + { + Gbl.RowEvenOdd = NumMatch % 2; + + /***** Get match data *****/ + row = mysql_fetch_row (mysql_res); + /* + row[0]: GamCod + row[1]: MchCod + row[2]: UsrCod + row[3]: UNIX_TIMESTAMP(StartTime) + row[4]: UNIX_TIMESTAMP(EndTime) + row[5]: Title + */ + /* Code of the game (row[0]) */ + if ((Match.GamCod = Str_ConvertStrCodToLongCod (row[0])) <= 0) + Err_WrongGameExit (); + + /* Code of the match (row[1]) */ + if ((Match.MchCod = Str_ConvertStrCodToLongCod (row[1])) <= 0) + Err_WrongMatchExit (); + + /* Get match teacher (row[2]) */ + Match.UsrCod = Str_ConvertStrCodToLongCod (row[2]); + + /* Get start/end times (row[3], row[4] hold start/end UTC times) */ + for (StartEndTime = (Dat_StartEndTime_t) 0; + StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1); + StartEndTime++) + Match.TimeUTC[StartEndTime] = Dat_GetUNIXTimeFromStr (row[3 + StartEndTime]); + + /* Get the title of the match (row[5]) */ + if (row[5]) + Str_Copy (Match.Title,row[5],sizeof (Match.Title) - 1); + else + Match.Title[0] = '\0'; + + /***** List match *****/ + HTM_TR_Begin (NULL); + + /* Game code */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt ("GamCod: "); + HTM_Long (Match.GamCod); + HTM_TD_End (); + + /* Match code */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt ("MchCod: "); + HTM_Long (Match.MchCod); + HTM_TD_End (); + + /* Match author */ + Mch_ListOneOrMoreMatchesAuthor (&Match); + + /* Start/end date/time */ + Mch_ListOneOrMoreMatchesTimes (&Match,UniqueId); + + /* Match title */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt (Match.Title); + HTM_TD_End (); + + /* Number of players who have played the match */ + Mch_ListOneOrMoreMatchesNumPlayers (&Match); + + /* Filling */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_TD_End (); + + HTM_TR_End (); + + /***** Match prints *****/ + MchPrn_ListPrintsToFix (Match.MchCod); + } + + /***** End table *****/ + HTM_TABLE_End (); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + /***** End box *****/ + Box_BoxEnd (); + } + +static void MchPrn_ListPrintsToFix (long MchCod) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumPrints; + unsigned NumPrint; + struct MchPrn_Print Print; + double StoredScore; + + /***** Get data of prints from database *****/ + NumPrints = Mch_DB_GetPrintsInMatch (&mysql_res,MchCod); + + /***** Write rows *****/ + for (NumPrint = 0; + NumPrint < NumPrints; + NumPrint++) + { + /***** Get match print data *****/ + Print.MchCod = MchCod; + row = mysql_fetch_row (mysql_res); + /* + row[0]: UsrCod + row[1]: NumQsts + row[2]: NumQstsNotBlank + row[3]: Score + */ + /* Get student code (row[0]) */ + Print.UsrCod = Str_ConvertStrCodToLongCod (row[0]); + + /* Get number of questions (row[1]) */ + if (sscanf (row[1],"%u",&Print.NumQsts.All) != 1) + Print.NumQsts.All = 0; + + /* Get number of questions not blank (row[2]) */ + if (sscanf (row[2],"%u",&Print.NumQsts.NotBlank) != 1) + Print.NumQsts.NotBlank = 0; + + /* Get score (row[3]) */ + Str_SetDecimalPointToUS (); // To get the decimal point as a dot + if (sscanf (row[3],"%lf",&StoredScore) != 1) + StoredScore = 0.0; + Str_SetDecimalPointToLocal (); // Return to local system + + /***** Write row *****/ + HTM_TR_Begin (NULL); + /* Indent */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_TD_End (); + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_TD_End (); + + /* Student */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + Usr_WriteAuthor1Line (Print.UsrCod,false); + HTM_TD_End (); + + /* Number of questions */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt ("NumQsts: "); + HTM_Unsigned (Print.NumQsts.All); + HTM_TD_End (); + + /* Number of questions not blank */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt ("NumQstsNotBlank: "); + HTM_Unsigned (Print.NumQsts.NotBlank); + HTM_TD_End (); + + /* Stored score */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt ("Stored score: "); + HTM_Double (StoredScore); + HTM_TD_End (); + + /* Compute score */ + Mch_GetMatchQuestionsFromDB (&Print); + MchPrn_ComputeScore (&Print); + + /* Computed score */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt ("Computed score: "); + HTM_Double (Print.Score); + HTM_TD_End (); + + /* Store computed score? */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + if (fabs (StoredScore-Print.Score) < 0.0000000001) + HTM_Txt ("="); + else + { + HTM_Txt ("!"); + Mch_DB_UpdateMatchPrintScore (&Print); + } + HTM_TD_End (); + + HTM_TR_End (); + } + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + } diff --git a/swad_match_print.h b/swad_match_print.h index 5c815e33..182a003f 100644 --- a/swad_match_print.h +++ b/swad_match_print.h @@ -59,4 +59,7 @@ void MchPrn_ComputeScoreAndUpdateMyMatchPrintInDB (long MchCod); void MchPrn_GetMatchPrintDataByMchCodAndUsrCod (struct MchPrn_Print *Print); +void MchPrn_PutLinkToFixMatchesPrintsScores (void); +void MchPrn_FixMatchesPrintsScores (void); + #endif diff --git a/swad_match_result.c b/swad_match_result.c index afbc5782..ae9e6bc8 100644 --- a/swad_match_result.c +++ b/swad_match_result.c @@ -119,7 +119,7 @@ void MchRes_ShowMyMchResultsInCrs (void) /***** List my matches results in the current course *****/ MchRes_ShowResultsBegin (&Games,Txt_Results,true); // List games to select - MchRes_ListMyMchResultsInCrs (&Games); + MchRes_ListMyMchResultsInCrs (&Games); MchRes_ShowResultsEnd (); /***** Free list of games *****/ @@ -172,7 +172,7 @@ void MchRes_ShowMyMchResultsInGam (void) Str_BuildStringStr (Txt_Results_of_game_X,Game.Title), false); // Do not list games to select Str_FreeString (); - MchRes_ListMyMchResultsInGam (&Games,Game.GamCod); + MchRes_ListMyMchResultsInGam (&Games,Game.GamCod); MchRes_ShowResultsEnd (); /***** Game end *****/ @@ -224,7 +224,7 @@ void MchRes_ShowMyMchResultsInMch (void) MchRes_ShowResultsBegin (&Games,Str_BuildStringStr (Txt_Results_of_match_X,Match.Title), false); // Do not list games to select Str_FreeString (); - MchRes_ListMyMchResultsInMch (&Games,Match.MchCod); + MchRes_ListMyMchResultsInMch (&Games,Match.MchCod); MchRes_ShowResultsEnd (); /***** Game end *****/ @@ -277,7 +277,7 @@ static void MchRes_ShowAllMchResultsInSelectedGames (void *Games) MchRes_ShowResultsBegin ((struct Gam_Games *) Games, Txt_Results, true); // List games to select - MchRes_ListAllMchResultsInSelectedGames ((struct Gam_Games *) Games); + MchRes_ListAllMchResultsInSelectedGames ((struct Gam_Games *) Games); MchRes_ShowResultsEnd (); /***** Free list of games *****/ @@ -376,7 +376,7 @@ void MchRes_ShowAllMchResultsInGam (void) Str_BuildStringStr (Txt_Results_of_game_X,Game.Title), false); // Do not list games to select Str_FreeString (); - MchRes_ListAllMchResultsInGam (&Games,Game.GamCod); + MchRes_ListAllMchResultsInGam (&Games,Game.GamCod); MchRes_ShowResultsEnd (); /***** Game end *****/ @@ -451,7 +451,7 @@ void MchRes_ShowAllMchResultsInMch (void) Str_BuildStringStr (Txt_Results_of_match_X,Match.Title), false); // Do not list games to select Str_FreeString (); - MchRes_ListAllMchResultsInMch (&Games,Match.MchCod); + MchRes_ListAllMchResultsInMch (&Games,Match.MchCod); MchRes_ShowResultsEnd (); /***** Game end *****/ @@ -913,7 +913,7 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, TotalScore, TotalGrade); } - else + else // No results { /* Columns for dates and match */ HTM_TD_Begin ("colspan=\"3\" class=\"LINE_BOTTOM COLOR%u\"", diff --git a/swad_question_database.c b/swad_question_database.c index 631caab5..49ae5f07 100644 --- a/swad_question_database.c +++ b/swad_question_database.c @@ -149,6 +149,32 @@ void Qst_DB_UpdateQstScore (long QstCod,bool AnswerIsNotBlank,double Score) Str_SetDecimalPointToLocal (); // Return to local system } +/*****************************************************************************/ +/************************* Fix the score of a question ***********************/ +/*****************************************************************************/ + +void Qst_DB_FixQstScore (long QstCod,bool AnswerIsNotBlank, + double BadScore,double GoodScore) + { + Str_SetDecimalPointToUS (); // To print the floating point as a dot + if (AnswerIsNotBlank) // User's answer is not blank + DB_QueryUPDATE ("can not update the score of a question", + "UPDATE tst_questions" + " SET Score=Score-(%.15lg)+(%.15lg)" + " WHERE QstCod=%ld", + BadScore,GoodScore, + QstCod); + /* + Ale_ShowAlert (Ale_INFO, + "UPDATE tst_questions" + " SET Score=Score-(%.15lg)+(%.15lg)" + " WHERE QstCod=%ld", + BadScore,GoodScore, + QstCod); + */ + Str_SetDecimalPointToLocal (); // Return to local system + } + /*****************************************************************************/ /*********************** Change the shuffle of a question ********************/ /*****************************************************************************/ diff --git a/swad_question_database.h b/swad_question_database.h index 1fd3ddf8..5b46cc72 100644 --- a/swad_question_database.h +++ b/swad_question_database.h @@ -30,6 +30,8 @@ long Qst_DB_CreateQst (const struct Qst_Question *Question); void Qst_DB_UpdateQst (const struct Qst_Question *Question); void Qst_DB_UpdateQstScore (long QstCod,bool AnswerIsNotBlank,double Score); +void Qst_DB_FixQstScore (long QstCod,bool AnswerIsNotBlank, + double BadScore,double GoodScore); void Qst_DB_UpdateQstShuffle (long QstCod,bool Shuffle); //----------------------------------------------------------------------------- void Qst_DB_CreateIntAnswer (struct Qst_Question *Question); diff --git a/swad_test.c b/swad_test.c index 4f545d31..fe7f44b3 100644 --- a/swad_test.c +++ b/swad_test.c @@ -276,7 +276,8 @@ void Tst_ReceiveTestDraft (void) else // Print not yet sent { /***** Get test print questions from database *****/ - TstPrn_GetPrintQuestionsFromDB (&Print); + if (!TstPrn_GetPrintQuestionsFromDB (&Print)) + Err_WrongExamExit (); /***** Get answers from form to assess a test *****/ TstPrn_GetAnswersFromForm (&Print); @@ -332,7 +333,8 @@ void Tst_AssessTest (void) else // Print not yet sent { /***** Get test print questions from database *****/ - TstPrn_GetPrintQuestionsFromDB (&Print); + if (!TstPrn_GetPrintQuestionsFromDB (&Print)) + Err_WrongExamExit (); /***** Get answers from form to assess a test *****/ TstPrn_GetAnswersFromForm (&Print); diff --git a/swad_test_database.c b/swad_test_database.c index 2f577a4e..ebe99f23 100644 --- a/swad_test_database.c +++ b/swad_test_database.c @@ -241,6 +241,54 @@ void Tst_DB_UpdatePrint (const struct TstPrn_Print *Print) Str_SetDecimalPointToLocal (); // Return to local system } +/*****************************************************************************/ +/************************** Update test print score **************************/ +/*****************************************************************************/ + +void Tst_DB_UpdatePrintScore (const struct TstPrn_Print *Print) + { + Str_SetDecimalPointToUS (); // To print the floating point as a dot + DB_QueryUPDATE ("can not update match print", + "UPDATE tst_exams" + " SET Score='%.15lg'" + " WHERE ExaCod=%ld", + Print->Score, + Print->PrnCod); + /* + HTM_TxtF ("UPDATE tst_exams" + " SET Score='%.15lg'" + " WHERE ExaCod=%ld", + Print->Score, + Print->PrnCod); + */ + Str_SetDecimalPointToLocal (); // Return to local system + } + +/*****************************************************************************/ +/************************ Get test prints between dates **********************/ +/*****************************************************************************/ + +unsigned Tst_DB_GetPrintsBetweenDates (MYSQL_RES **mysql_res, + const char *From, + const char *To) + { + return (unsigned) + DB_QuerySELECT (mysql_res,"can not get prints", + "SELECT ExaCod," // row[0] + "UsrCod," // row[1] + "UNIX_TIMESTAMP(StartTime)," // row[2] + "UNIX_TIMESTAMP(EndTime)," // row[3] + "NumQsts," // row[4] + "NumQstsNotBlank," // row[5] + "Score" // row[6] + " FROM tst_exams" + " WHERE StartTime>='%s'" + " AND StartTime<='%s'" + " ORDER BY ExaCod", + From, + To); + } + /*****************************************************************************/ /************ Get the test prints of a user in the current course ************/ /*****************************************************************************/ @@ -351,6 +399,41 @@ void Tst_DB_StoreOneQstOfPrint (const struct TstPrn_Print *Print,unsigned QstInd Str_SetDecimalPointToLocal (); // Return to local system } +/*****************************************************************************/ +/************ Store user's answers of an test print into database ************/ +/*****************************************************************************/ + +void Tst_DB_FixOneQstOfPrint (const struct TstPrn_Print *Print,unsigned QstInd) + { + /***** Insert question and user's answers into database *****/ + Str_SetDecimalPointToUS (); // To print the floating point as a dot + DB_QueryREPLACE ("can not update a question of a test", + "REPLACE INTO tst_exam_questions" + " (ExaCod,QstCod,QstInd,Score,Indexes,Answers)" + " VALUES" + " (%ld,%ld,%u,'%.15lg','%s','%s')", + Print->PrnCod, + Print->PrintedQuestions[QstInd].QstCod, + QstInd, // 0, 1, 2, 3... + Print->PrintedQuestions[QstInd].Score, + Print->PrintedQuestions[QstInd].StrIndexes, + Print->PrintedQuestions[QstInd].StrAnswers); + /* + Ale_ShowAlert (Ale_INFO, + "REPLACE INTO tst_exam_questions" + " (ExaCod,QstCod,QstInd,Score,Indexes,Answers)" + " VALUES" + " (%ld,%ld,%u,'%.15lg','%s','%s')", + Print->PrnCod, + Print->PrintedQuestions[QstInd].QstCod, + QstInd, // 0, 1, 2, 3... + Print->PrintedQuestions[QstInd].Score, + Print->PrintedQuestions[QstInd].StrIndexes, + Print->PrintedQuestions[QstInd].StrAnswers); + */ + Str_SetDecimalPointToLocal (); // Return to local system + } + /*****************************************************************************/ /**************** Get all tags of questions in a test print ******************/ /*****************************************************************************/ @@ -358,7 +441,7 @@ void Tst_DB_StoreOneQstOfPrint (const struct TstPrn_Print *Print,unsigned QstInd unsigned Tst_DB_GetTagsPresentInAPrint (MYSQL_RES **mysql_res,long PrnCod) { return (unsigned) - DB_QuerySELECT (mysql_res,"can not get tags present in a test", + DB_QuerySELECT (mysql_res,"can not get tags present in a test print", "SELECT tst_tags.TagTxt" // row[0] " FROM (SELECT DISTINCT " "tst_question_tags.TagCod" @@ -379,7 +462,7 @@ unsigned Tst_DB_GetTagsPresentInAPrint (MYSQL_RES **mysql_res,long PrnCod) unsigned Tst_DB_GetPrintQuestions (MYSQL_RES **mysql_res,long PrnCod) { return (unsigned) - DB_QuerySELECT (mysql_res,"can not get questions of a test", + DB_QuerySELECT (mysql_res,"can not get questions of a test print", "SELECT QstCod," // row[0] "Score," // row[1] "Indexes," // row[2] diff --git a/swad_test_database.h b/swad_test_database.h index f7203c62..bc0617e2 100644 --- a/swad_test_database.h +++ b/swad_test_database.h @@ -50,7 +50,11 @@ void Tst_DB_RemoveTstConfig (long CrsCod); //------------------------------- Test prints --------------------------------- long Tst_DB_CreatePrint (unsigned NumQsts); void Tst_DB_UpdatePrint (const struct TstPrn_Print *Print); +void Tst_DB_UpdatePrintScore (const struct TstPrn_Print *Print); +unsigned Tst_DB_GetPrintsBetweenDates (MYSQL_RES **mysql_res, + const char *From, + const char *To); unsigned Tst_DB_GetUsrPrintsInCurrentCrs (MYSQL_RES **mysql_res,long UsrCod); unsigned Tst_DB_GetPrintDataByPrnCod (MYSQL_RES **mysql_res,long PrnCod); @@ -60,6 +64,7 @@ void Tst_DB_RemovePrintsMadeByInCrs (long CrsCod); //-------------------------- Test print questions ----------------------------- void Tst_DB_StoreOneQstOfPrint (const struct TstPrn_Print *Print,unsigned QstInd); +void Tst_DB_FixOneQstOfPrint (const struct TstPrn_Print *Print,unsigned QstInd); unsigned Tst_DB_GetTagsPresentInAPrint (MYSQL_RES **mysql_res,long PrnCod); unsigned Tst_DB_GetPrintQuestions (MYSQL_RES **mysql_res,long PrnCod); diff --git a/swad_test_print.c b/swad_test_print.c index 8d0c657b..0d2e3fe6 100644 --- a/swad_test_print.c +++ b/swad_test_print.c @@ -26,6 +26,7 @@ /*****************************************************************************/ #define _GNU_SOURCE // For asprintf +#include // For fabs #include // For boolean type #include // For NULL #include // For asprintf @@ -167,6 +168,8 @@ static void TstRes_CheckIfICanSeePrintResult (const struct TstPrn_Print *Print, static void TstPrn_ShowTagsPresentInAPrint (long PrnCod); +static void TstPrn_ComputeScoresAndFixQuestionsOfPrint (struct TstPrn_Print *Print); + /*****************************************************************************/ /***************************** Reset test print ******************************/ /*****************************************************************************/ @@ -2174,7 +2177,8 @@ void TstPrn_ShowOnePrint (void) if (ICanView.Result) // I am allowed to view this test print result { /***** Get questions and user's answers of the test from database *****/ - TstPrn_GetPrintQuestionsFromDB (&Print); + if (!TstPrn_GetPrintQuestionsFromDB (&Print)) + Err_WrongExamExit (); /***** Begin box *****/ Box_BoxBegin (NULL,Txt_Result, @@ -2490,7 +2494,7 @@ void TstPrn_GetPrintDataByPrnCod (struct TstPrn_Print *Print) /************* Get the questions of a test print from database ***************/ /*****************************************************************************/ -void TstPrn_GetPrintQuestionsFromDB (struct TstPrn_Print *Print) +bool TstPrn_GetPrintQuestionsFromDB (struct TstPrn_Print *Print) { MYSQL_RES *mysql_res; MYSQL_ROW row; @@ -2529,8 +2533,7 @@ void TstPrn_GetPrintQuestionsFromDB (struct TstPrn_Print *Print) /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); - if (NumQsts != Print->NumQsts.All) - Err_WrongExamExit (); + return (NumQsts == Print->NumQsts.All); } /*****************************************************************************/ @@ -2608,3 +2611,226 @@ unsigned TstPrn_GetNumPrintsGeneratedByMe (void) return NumPrintsGeneratedByMe; } + +/*****************************************************************************/ +/********* Recompute scores stored in test prints made on 2021-11-25 *********/ +/*****************************************************************************/ + +void TstPrn_PutLinkToFixTestsPrintsScores (void) + { + Lay_PutContextualLinkIconText (ActFixTstSco,NULL, + NULL,NULL, + "recycle.svg", + "Recalcular puntuación tests"); + } + +void TstPrn_FixTestsPrintsScores (void) + { + extern const char *Txt_Results; + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumPrints; + unsigned NumPrint; + unsigned UniqueId; + char *Id; + struct TstPrn_Print Print; + long UsrCod; + Dat_StartEndTime_t StartEndTime; + double StoredScore; + + /***** Reset match *****/ + Box_BoxBegin ("100%",Txt_Results, + NULL,NULL, + NULL,Box_NOT_CLOSABLE); + + /***** Get data of matches from database *****/ + NumPrints = Tst_DB_GetPrintsBetweenDates (&mysql_res, + "2021-11-24 20:00:00", // From + "2021-11-25 16:00:00"); // To + + /***** Begin table *****/ + HTM_TABLE_BeginWidePadding (2); + + /***** Write rows *****/ + for (NumPrint = 0, UniqueId = 1; + NumPrint < NumPrints; + NumPrint++, UniqueId++) + { + Gbl.RowEvenOdd = NumPrint % 2; + + /***** Get match data *****/ + row = mysql_fetch_row (mysql_res); + /* + row[0]: ExaCod + row[1]: UsrCod + row[2]: UNIX_TIMESTAMP(StartTime) + row[3]: UNIX_TIMESTAMP(EndTime) + row[4]: NumQsts + row[5]: NumQstsNotBlank + row[6]: Score + */ + /* Code of the print (row[0]) */ + if ((Print.PrnCod = Str_ConvertStrCodToLongCod (row[0])) <= 0) + Err_WrongGameExit (); + + /* Get user code (row[1]) */ + UsrCod = Str_ConvertStrCodToLongCod (row[1]); + + /* Get start/end times (row[2], row[3] hold start/end UTC times) */ + for (StartEndTime = (Dat_StartEndTime_t) 0; + StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1); + StartEndTime++) + Print.TimeUTC[StartEndTime] = Dat_GetUNIXTimeFromStr (row[2 + StartEndTime]); + + /* Get number of questions (row[4]) */ + if (sscanf (row[4],"%u",&Print.NumQsts.All) != 1) + Print.NumQsts.All = 0; + + /* Get number of questions not blank (row[5]) */ + if (sscanf (row[5],"%u",&Print.NumQsts.NotBlank) != 1) + Print.NumQsts.NotBlank = 0; + + /* Get score (row[6]) */ + Str_SetDecimalPointToUS (); // To get the decimal point as a dot + if (sscanf (row[6],"%lf",&StoredScore) != 1) + StoredScore = 0.0; + Str_SetDecimalPointToLocal (); // Return to local system + + /***** List print *****/ + HTM_TR_Begin (NULL); + + /* Print code */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt ("PrnCod: "); + HTM_Long (Print.PrnCod); + HTM_TD_End (); + + /* Student */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + Usr_WriteAuthor1Line (UsrCod,false); + HTM_TD_End (); + + /* Write dates and times */ + for (StartEndTime = (Dat_StartEndTime_t) 0; + StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1); + StartEndTime++) + { + if (asprintf (&Id,"tst_date_%u_%u",(unsigned) StartEndTime,UniqueId) < 0) + Err_NotEnoughMemoryExit (); + HTM_TD_Begin ("id=\"%s\" class=\"DAT LT COLOR%u\"", + Id,Gbl.RowEvenOdd); + Dat_WriteLocalDateHMSFromUTC (Id,Print.TimeUTC[StartEndTime], + Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK, + true,true,false,0x7); + HTM_TD_End (); + free (Id); + } + + /* Number of questions */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt ("NumQsts: "); + HTM_Unsigned (Print.NumQsts.All); + HTM_TD_End (); + + /* Number of questions not blank */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt ("NumQstsNotBlank: "); + HTM_Unsigned (Print.NumQsts.NotBlank); + HTM_TD_End (); + + /* Stored score */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Txt ("Stored score: "); + HTM_Double (StoredScore); + HTM_TD_End (); + + /* Compute score */ + if (TstPrn_GetPrintQuestionsFromDB (&Print)) + { + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + TstPrn_ComputeScoresAndFixQuestionsOfPrint (&Print); + HTM_Txt ("Computed score: "); + HTM_Double (Print.Score); + HTM_TD_End (); + + /* Store computed score? */ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + if (fabs (StoredScore-Print.Score) < 0.0000000001) + HTM_Txt ("="); + else + { + HTM_Txt ("!"); + Tst_DB_UpdatePrintScore (&Print); + } + HTM_TD_End (); + } + else + { + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + Ale_ShowAlert (Ale_ERROR,"Wrong exam."); + HTM_TD_End (); + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_TD_End (); + } + + HTM_TR_End (); + } + + /***** End table *****/ + HTM_TABLE_End (); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + /***** End box *****/ + Box_BoxEnd (); + } + +/*****************************************************************************/ +/*********** Compute score of each question and store in database ************/ +/*****************************************************************************/ + +static void TstPrn_ComputeScoresAndFixQuestionsOfPrint (struct TstPrn_Print *Print) + { + unsigned QstInd; + struct Qst_Question Question; + double BadScore; + double GoodScore; + + /***** Initialize total score *****/ + Print->Score = 0.0; + Print->NumQsts.NotBlank = 0; + + /***** Compute and store scores of all questions *****/ + for (QstInd = 0; + QstInd < Print->NumQsts.All; + QstInd++) + { + /* Make a copy of score retrieved from database before computing it */ + BadScore = Print->PrintedQuestions[QstInd].Score; + + /* Compute question score */ + Qst_QstConstructor (&Question); + Question.QstCod = Print->PrintedQuestions[QstInd].QstCod; + Question.Answer.Type = Qst_DB_GetQstAnswerType (Question.QstCod); + TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[QstInd],&Question); + Qst_QstDestructor (&Question); + + /* Make a copy of just computed score */ + GoodScore = Print->PrintedQuestions[QstInd].Score; + + /* Store test question in database */ + Tst_DB_FixOneQstOfPrint (Print, + QstInd); // 0, 1, 2, 3... + + /* Accumulate total score */ + Print->Score += Print->PrintedQuestions[QstInd].Score; + if (Print->PrintedQuestions[QstInd].StrAnswers[0]) // User's answer is not blank + Print->NumQsts.NotBlank++; + + /* Update the number of hits and the score of this question in tests database */ + Qst_DB_FixQstScore (Print->PrintedQuestions[QstInd].QstCod, + Print->PrintedQuestions[QstInd].StrAnswers[0] != '\0', + BadScore,GoodScore); + } + } diff --git a/swad_test_print.h b/swad_test_print.h index c048a43d..135dfee2 100644 --- a/swad_test_print.h +++ b/swad_test_print.h @@ -151,11 +151,14 @@ void TstPrn_ShowPrintAnswers (struct UsrData *UsrDat, unsigned Visibility); void TstPrn_GetPrintDataByPrnCod (struct TstPrn_Print *Print); -void TstPrn_GetPrintQuestionsFromDB (struct TstPrn_Print *Print); +bool TstPrn_GetPrintQuestionsFromDB (struct TstPrn_Print *Print); void TstPrn_RemovePrintsMadeByUsrInAllCrss (long UsrCod); void TstPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod); void TstPrn_RemoveCrsPrints (long CrsCod); unsigned TstPrn_GetNumPrintsGeneratedByMe (void); +void TstPrn_PutLinkToFixTestsPrintsScores (void); +void TstPrn_FixTestsPrintsScores (void); + #endif