Version 21.63: Nov 26, 2021 Fixing of corruption in test prints and match prints.

This commit is contained in:
acanas 2021-11-26 01:53:31 +01:00
parent d0e3b8da03
commit 5517a2d430
19 changed files with 785 additions and 62 deletions

View File

@ -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);

View File

@ -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
};
/*****************************************************************************/

View File

@ -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 ********************************/

View File

@ -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)

View File

@ -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 ();
}

View File

@ -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 *****************/
/*****************************************************************************/

View File

@ -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

View File

@ -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 **************/
/*****************************************************************************/

View File

@ -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);

View File

@ -25,8 +25,11 @@
/********************************* Headers ***********************************/
/*****************************************************************************/
#include <math.h> // 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&oacute;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);
}

View File

@ -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

View File

@ -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\"",

View File

@ -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 ********************/
/*****************************************************************************/

View File

@ -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);

View File

@ -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);

View File

@ -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]

View File

@ -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);

View File

@ -26,6 +26,7 @@
/*****************************************************************************/
#define _GNU_SOURCE // For asprintf
#include <math.h> // For fabs
#include <stdbool.h> // For boolean type
#include <stddef.h> // For NULL
#include <stdio.h> // 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&oacute;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);
}
}

View File

@ -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