diff --git a/swad_changelog.h b/swad_changelog.h index 5aabf84e5..19574d063 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -556,7 +556,7 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - * En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 19.254 (2020-06-22)" +#define Log_PLATFORM_VERSION "SWAD 19.254.1 (2020-06-23)" #define CSS_FILE "swad19.253.css" #define JS_FILE "swad19.254.js" /* @@ -566,9 +566,9 @@ TODO: Fix bug: Un estudiante recibe una notificaci TODO: Fix bug: Cuando se pulsa en ver fichas, y luego en una ficha en "Ver trabajos" o "Ver exámenes", o lo que sea, sale dos veces ese estudiante. TODO: No limitar el número de preguntas en un examen a ExaPrn_MAX_QUESTIONS_PER_EXAM_PRINT, sino asignar PrintedQuestions dinámicamente con malloc TODO: Que al generar un examen sólo se cojan preguntas válidas. Y si ya está generado, al entrar de nuevo, que se vean en rojo. -TODO: Refactorizar MchRes_CheckIfICanSeeMatchResult y MchRes_CheckIfICanViewScore uniéndolas en una función como ExaRes_CheckIfICanSeePrintResult - Y dentro de las funciones TstPrn_ShowUsrPrints y TstPrn_ShowOnePrint crear y llamar a una función común similar a ExaRes_CheckIfICanSeePrintResult +TODO: Dentro de las funciones TstPrn_ShowUsrPrints y TstPrn_ShowOnePrint crear y llamar a una función común similar a ExaRes_CheckIfICanSeePrintResult + Version 19.254.1: Jun 23, 2020 Code refactoring in matches results. (303646 lines) Version 19.254: Jun 22, 2020 Fixed bug in Javascript related to quotes. Reported by Laura García Rejón. (303653 lines) Version 19.253: Jun 22, 2020 More details in listing of exams. (303643 lines) Version 19.252.1: Jun 19, 2020 Changes in listing of exams and matches results. (303245 lines) diff --git a/swad_exam_result.c b/swad_exam_result.c index 1e20c3ae0..94853b3e6 100644 --- a/swad_exam_result.c +++ b/swad_exam_result.c @@ -1643,7 +1643,7 @@ static void ExaRes_CheckIfICanSeePrintResult (const struct Exa_Exam *Exam, { bool ItsMe; - /***** Check if I can view this print result *****/ + /***** Check if I can view print result and score *****/ switch (Gbl.Usrs.Me.Role.Logged) { case Rol_STD: diff --git a/swad_game.c b/swad_game.c index 1ff66ac03..78ba33bb3 100644 --- a/swad_game.c +++ b/swad_game.c @@ -925,6 +925,13 @@ void Gam_GetListSelectedGamCods (struct Gam_Games *Games) long GamCod; char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1]; + /***** Default selected *****/ + Games->NumSelected = 0; + + /***** Trivial check: there are games visibles by me *****/ + if (!Games->Num) + return; + /***** Allocate memory for list of games selected *****/ MaxSizeListGamCodsSelected = Games->Num * (Cns_MAX_DECIMAL_DIGITS_LONG + 1); if ((Games->GamCodsSelected = (char *) malloc (MaxSizeListGamCodsSelected + 1)) == NULL) @@ -941,7 +948,6 @@ void Gam_GetListSelectedGamCods (struct Gam_Games *Games) NumGame < Games->Num; NumGame++) Games->Lst[NumGame].Selected = false; - Games->NumSelected = 0; /* Set some games as selected */ for (Ptr = Games->GamCodsSelected; diff --git a/swad_match_result.c b/swad_match_result.c index c97635c79..d42a3a881 100644 --- a/swad_match_result.c +++ b/swad_match_result.c @@ -59,6 +59,12 @@ extern struct Globals Gbl; /******************************* Private types *******************************/ /*****************************************************************************/ +struct MchRes_ICanView + { + bool Result; + bool Score; + }; + /*****************************************************************************/ /***************************** Private constants *****************************/ /*****************************************************************************/ @@ -105,8 +111,10 @@ static void MchRes_ShowMchResultsSummaryRow (unsigned NumResults, static void MchRes_GetMatchResultDataByMchCod (long MchCod,long UsrCod, struct TstPrn_Print *Print); -static bool MchRes_CheckIfICanSeeMatchResult (struct Mch_Match *Match,long UsrCod); -static bool MchRes_CheckIfICanViewScore (bool ICanViewResult,unsigned Visibility); +static void MchRes_CheckIfICanSeeMatchResult (const struct Gam_Game *Game, + const struct Mch_Match *Match, + long UsrCod, + struct MchRes_ICanView *ICanView); /*****************************************************************************/ /*********** Compute score and create/update my result in a match ************/ @@ -799,16 +807,17 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, extern const char *Txt_Result; char *MchSubQuery; char *GamSubQuery; + char *HidGamSubQuery; MYSQL_RES *mysql_res; MYSQL_ROW row; struct UsrData *UsrDat; - bool ICanViewResult; - bool ICanViewScore; + struct MchRes_ICanView ICanView; unsigned NumResults; unsigned NumResult; static unsigned UniqueId = 0; char *Id; struct Mch_Match Match; + struct Gam_Game Game; Dat_StartEndTime_t StartEndTime; unsigned NumQstsInThisResult; unsigned NumQstsNotBlankInThisResult; @@ -816,10 +825,8 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, unsigned NumTotalQstsNotBlank = 0; double ScoreInThisResult; double TotalScoreOfAllResults = 0.0; - double MaxGrade; double Grade; double TotalGrade = 0.0; - unsigned Visibility; time_t TimeUTC[Dat_NUM_START_END_TIME]; /***** Reset match *****/ @@ -867,6 +874,22 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, Lay_NotEnoughMemoryExit (); } + /***** Subquery: get hidden games? + · A student will not be able to see their results in hidden games + · A teacher will be able to see results from other users even in hidden games + *****/ + switch (MeOrOther) + { + case Usr_ME: // A student watching her/his results + if (asprintf (&HidGamSubQuery," AND gam_games.Hidden='N'") < 0) + Lay_NotEnoughMemoryExit (); + break; + default: // A teacher/admin watching the results of other users + if (asprintf (&HidGamSubQuery,"%s","") < 0) + Lay_NotEnoughMemoryExit (); + break; + } + /***** Make database query *****/ NumResults = (unsigned) DB_QuerySELECT (&mysql_res,"can not get matches results", @@ -875,21 +898,22 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, "UNIX_TIMESTAMP(mch_results.EndTime)," // row[2] "mch_results.NumQsts," // row[3] "mch_results.NumQstsNotBlank," // row[4] - "mch_results.Score," // row[5] - "gam_games.MaxGrade," // row[6] - "gam_games.Visibility" // row[7] + "mch_results.Score" // row[5] " FROM mch_results,mch_matches,gam_games" " WHERE mch_results.UsrCod=%ld" "%s" // Match subquery " AND mch_results.MchCod=mch_matches.MchCod" "%s" // Games subquery " AND mch_matches.GamCod=gam_games.GamCod" + "%s" // Hidden games subquery " AND gam_games.CrsCod=%ld" // Extra check " ORDER BY mch_matches.Title", UsrDat->UsrCod, MchSubQuery, GamSubQuery, + HidGamSubQuery, Gbl.Hierarchy.Crs.CrsCod); + free (HidGamSubQuery); free (GamSubQuery); free (MchSubQuery); @@ -911,12 +935,13 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, Lay_ShowErrorAndExit ("Wrong code of match."); Mch_GetDataOfMatchByCod (&Match); - /* Get visibility (row[7]) */ - Visibility = TstVis_GetVisibilityFromStr (row[7]); + /* Get data of match and game */ + Mch_GetDataOfMatchByCod (&Match); + Game.GamCod = Match.GamCod; + Gam_GetDataOfGameByCod (&Game); - /* Show match result? */ - ICanViewResult = MchRes_CheckIfICanSeeMatchResult (&Match,UsrDat->UsrCod); - ICanViewScore = MchRes_CheckIfICanViewScore (ICanViewResult,Visibility); + /* Check if I can view this match result and score */ + MchRes_CheckIfICanSeeMatchResult (&Game,&Match,UsrDat->UsrCod,&ICanView); if (NumResult) HTM_TR_Begin (NULL); @@ -944,7 +969,7 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, HTM_Txt (Match.Title); HTM_TD_End (); - if (ICanViewScore) + if (ICanView.Score) { /* Get number of questions (row[3]) */ if (sscanf (row[3],"%u",&NumQstsInThisResult) != 1) @@ -963,16 +988,12 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, ScoreInThisResult = 0.0; TotalScoreOfAllResults += ScoreInThisResult; - /* Get maximum grade (row[6]) */ - if (sscanf (row[6],"%lf",&MaxGrade) != 1) - MaxGrade = 0.0; - Str_SetDecimalPointToLocal (); // Return to local system } /* Write number of questions */ HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); - if (ICanViewScore) + if (ICanView.Score) HTM_Unsigned (NumQstsInThisResult); else Ico_PutIconNotVisible (); @@ -980,7 +1001,7 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, /* Write number of questions not blank */ HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); - if (ICanViewScore) + if (ICanView.Score) HTM_Unsigned (NumQstsNotBlankInThisResult); else Ico_PutIconNotVisible (); @@ -988,7 +1009,7 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, /* Write score */ HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); - if (ICanViewScore) + if (ICanView.Score) { HTM_Double2Decimals (ScoreInThisResult); HTM_Txt ("/"); @@ -1000,7 +1021,7 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, /* Write average score per question */ HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); - if (ICanViewScore) + if (ICanView.Score) HTM_Double2Decimals (NumQstsInThisResult ? ScoreInThisResult / (double) NumQstsInThisResult : 0.0); @@ -1010,10 +1031,10 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, /* Write grade over maximum grade */ HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); - if (ICanViewScore) + if (ICanView.Score) { - Grade = TstPrn_ComputeGrade (NumQstsInThisResult,ScoreInThisResult,MaxGrade); - TstPrn_ShowGrade (Grade,MaxGrade); + Grade = TstPrn_ComputeGrade (NumQstsInThisResult,ScoreInThisResult,Game.MaxGrade); + TstPrn_ShowGrade (Grade,Game.MaxGrade); TotalGrade += Grade; } else @@ -1022,7 +1043,7 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games, /* Link to show this result */ HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); - if (ICanViewResult) + if (ICanView.Result) { Games->GamCod = Match.GamCod; Games->MchCod = Match.MchCod; @@ -1151,8 +1172,7 @@ void MchRes_ShowOneMchResult (void) struct TstPrn_Print Print; bool ShowPhoto; char PhotoURL[PATH_MAX + 1]; - bool ICanViewResult; - bool ICanViewScore; + struct MchRes_ICanView ICanView; /***** Reset games context *****/ Gam_ResetGames (&Games); @@ -1183,35 +1203,10 @@ void MchRes_ShowOneMchResult (void) TstPrn_ResetPrint (&Print); MchRes_GetMatchResultDataByMchCod (Match.MchCod,UsrDat->UsrCod,&Print); - /***** Check if I can view this match result *****/ - switch (Gbl.Usrs.Me.Role.Logged) - { - case Rol_STD: - // Depends on visibility of result for this match (eye icon) - ICanViewResult = MchRes_CheckIfICanSeeMatchResult (&Match,UsrDat->UsrCod); + /***** Check if I can view this match result and score *****/ + MchRes_CheckIfICanSeeMatchResult (&Game,&Match,UsrDat->UsrCod,&ICanView); - if (ICanViewResult) - // Depends on 5 visibility icons - ICanViewScore = TstVis_IsVisibleTotalScore (Game.Visibility); - else - ICanViewScore = false; - break; - case Rol_NET: - case Rol_TCH: - case Rol_DEG_ADM: - case Rol_CTR_ADM: - case Rol_INS_ADM: - case Rol_SYS_ADM: - ICanViewResult = - ICanViewScore = true; - break; - default: - ICanViewResult = - ICanViewScore = false; - break; - } - - if (ICanViewResult) // I am allowed to view this match result + if (ICanView.Result) // I am allowed to view this match result { /***** Get questions and user's answers of the match result from database *****/ Mch_GetMatchQuestionsFromDB (Match.MchCod,UsrDat->UsrCod,&Print); @@ -1315,7 +1310,7 @@ void MchRes_ShowOneMchResult (void) HTM_TD_End (); HTM_TD_Begin ("class=\"DAT LB\""); - if (ICanViewScore) + if (ICanView.Score) { HTM_STRONG_Begin (); HTM_Double2Decimals (Print.Score); @@ -1337,7 +1332,7 @@ void MchRes_ShowOneMchResult (void) HTM_TD_End (); HTM_TD_Begin ("class=\"DAT LB\""); - if (ICanViewScore) + if (ICanView.Score) { HTM_STRONG_Begin (); TstPrn_ComputeAndShowGrade (Print.NumQsts,Print.Score,Game.MaxGrade); @@ -1440,41 +1435,30 @@ static void MchRes_GetMatchResultDataByMchCod (long MchCod,long UsrCod, /********************** Get if I can see match result ************************/ /*****************************************************************************/ -static bool MchRes_CheckIfICanSeeMatchResult (struct Mch_Match *Match,long UsrCod) +static void MchRes_CheckIfICanSeeMatchResult (const struct Gam_Game *Game, + const struct Mch_Match *Match, + long UsrCod, + struct MchRes_ICanView *ICanView) { bool ItsMe; + /***** Check if I can view print result and score *****/ switch (Gbl.Usrs.Me.Role.Logged) { case Rol_STD: + // Depends on visibility of game and result (eye icons) ItsMe = Usr_ItsMe (UsrCod); - return ItsMe && Match->Status.ShowUsrResults; + ICanView->Result = (ItsMe && // The result is mine + !Game->Hidden && // The game is visible + Match->Status.ShowUsrResults); // The results of the match are visible to users // Whether I belong or not to groups of match is not checked here... // ...because I should be able to see old matches made in old groups to which I belonged - case Rol_NET: - case Rol_TCH: - case Rol_DEG_ADM: - case Rol_CTR_ADM: - case Rol_INS_ADM: - case Rol_SYS_ADM: - return true; - default: - return false; - } - } -/*****************************************************************************/ -/********************** Get if I can see match result ************************/ -/*****************************************************************************/ - -static bool MchRes_CheckIfICanViewScore (bool ICanViewResult,unsigned Visibility) - { - switch (Gbl.Usrs.Me.Role.Logged) - { - case Rol_STD: - if (ICanViewResult) - return TstVis_IsVisibleTotalScore (Visibility); - return false; + if (ICanView->Result) + // Depends on 5 visibility icons associated to game + ICanView->Score = TstVis_IsVisibleTotalScore (Game->Visibility); + else + ICanView->Score = false; break; case Rol_NET: case Rol_TCH: @@ -1482,8 +1466,12 @@ static bool MchRes_CheckIfICanViewScore (bool ICanViewResult,unsigned Visibility case Rol_CTR_ADM: case Rol_INS_ADM: case Rol_SYS_ADM: - return true; + ICanView->Result = + ICanView->Score = true; + break; default: - return false; + ICanView->Result = + ICanView->Score = false; + break; } } diff --git a/swad_text.c b/swad_text.c index 807285901..fda8049f2 100644 --- a/swad_text.c +++ b/swad_text.c @@ -30889,7 +30889,7 @@ const char *Txt_Please_check_your_email_address = #elif L==4 // es "Por favor, compruebe su dirección de correo."; #elif L==5 // fr - "S'il vous plaít, v&eaxcute;rifiez votre adresse email."; + "S'il vous plaít, vérifiez votre adresse email."; #elif L==6 // gn "Por favor, compruebe su dirección de correo."; // Okoteve traducción #elif L==7 // it