Version19.250.3

This commit is contained in:
acanas 2020-06-18 02:06:02 +02:00
parent d1514dfbc1
commit 4e51c2192d
4 changed files with 119 additions and 70 deletions

View File

@ -556,15 +556,17 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD: En OpenSWAD:
ps2pdf source.ps destination.pdf ps2pdf source.ps destination.pdf
*/ */
#define Log_PLATFORM_VERSION "SWAD 19.250.2 (2020-06-17)" #define Log_PLATFORM_VERSION "SWAD 19.250.3 (2020-06-18)"
#define CSS_FILE "swad19.250.css" #define CSS_FILE "swad19.250.css"
#define JS_FILE "swad19.246.1.js" #define JS_FILE "swad19.246.1.js"
/* /*
TODO: Encarnación Hidalgo Tenorio: Antonio, ¿podría @swad_ugr mandar una notificación cuando el alumnado ha mandado su tarea? TODO: Encarnación Hidalgo Tenorio: Antonio, ¿podría @swad_ugr mandar una notificación cuando el alumnado ha mandado su tarea?
Se trataría de añadir un par de líneas "Nuevos archivos en actividades", "Nuevos archivos en otros trabajos". Se trataría de añadir un par de líneas "Nuevos archivos en actividades", "Nuevos archivos en otros trabajos".
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: 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
Version 19.250.2: Jun 17, 2020 Show valid score and valid grade in exam result. (303069 lines) Version 19.250.3: Jun 18, 2020 Show valid score and valid grade in listing of exam results. (303113 lines)
Version 19.250.2: Jun 17, 2020 Show valid score and valid grade in one exam result. (303069 lines)
Version 19.250.1: Jun 17, 2020 Fixed bug in attendance events, reported by Carlos A. Pozzo. (302977 lines) Version 19.250.1: Jun 17, 2020 Fixed bug in attendance events, reported by Carlos A. Pozzo. (302977 lines)
Version 19.250: Jun 17, 2020 Exam questions can be invalidated. Not finished. (302974 lines) Version 19.250: Jun 17, 2020 Exam questions can be invalidated. Not finished. (302974 lines)
1 change necessary in database: 1 change necessary in database:

View File

@ -163,8 +163,8 @@ static void ExaPrn_ResetPrintExceptEvtCodAndUsrCod (struct ExaPrn_Print *Print)
Print->TimeUTC[Dat_START_TIME] = Print->TimeUTC[Dat_START_TIME] =
Print->TimeUTC[Dat_END_TIME ] = (time_t) 0; Print->TimeUTC[Dat_END_TIME ] = (time_t) 0;
Print->NumQsts = Print->NumQsts =
Print->NumQstsNotBlank = Print->NumQstsValid =
Print->NumQstsValid = 0; Print->NumQstsNotBlank = 0;
Print->Sent = false; // After creating an exam print, it's not sent Print->Sent = false; // After creating an exam print, it's not sent
Print->Score = Print->Score =
Print->ScoreValid = 0.0; Print->ScoreValid = 0.0;
@ -544,11 +544,10 @@ void ExaPrn_GetPrintQuestionsFromDB (struct ExaPrn_Print *Print)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
unsigned NumQsts;
unsigned NumQst; unsigned NumQst;
/***** Get questions of an exam print from database *****/ /***** Get questions of an exam print from database *****/
NumQsts = Print->NumQsts =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get questions" (unsigned) DB_QuerySELECT (&mysql_res,"can not get questions"
" of an exam print", " of an exam print",
"SELECT QstCod," // row[0] "SELECT QstCod," // row[0]
@ -562,9 +561,9 @@ void ExaPrn_GetPrintQuestionsFromDB (struct ExaPrn_Print *Print)
Print->PrnCod); Print->PrnCod);
/***** Get questions *****/ /***** Get questions *****/
if (NumQsts == Print->NumQsts) if (Print->NumQsts <= ExaPrn_MAX_QUESTIONS_PER_EXAM_PRINT)
for (NumQst = 0; for (NumQst = 0;
NumQst < NumQsts; NumQst < Print->NumQsts;
NumQst++) NumQst++)
{ {
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
@ -595,8 +594,8 @@ void ExaPrn_GetPrintQuestionsFromDB (struct ExaPrn_Print *Print)
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
if (NumQsts != Print->NumQsts) if (Print->NumQsts > ExaPrn_MAX_QUESTIONS_PER_EXAM_PRINT)
Lay_WrongExamExit (); Lay_ShowErrorAndExit ("Too many questions.");
} }
/*****************************************************************************/ /*****************************************************************************/

View File

@ -42,8 +42,8 @@ struct ExaPrn_Print
long UsrCod; // User who answered the exam print long UsrCod; // User who answered the exam print
time_t TimeUTC[Dat_NUM_START_END_TIME]; time_t TimeUTC[Dat_NUM_START_END_TIME];
unsigned NumQsts; // Number of questions unsigned NumQsts; // Number of questions
unsigned NumQstsNotBlank; // Number of questions not blank
unsigned NumQstsValid; // Number of valid questions (not invalidated by teachers) unsigned NumQstsValid; // Number of valid questions (not invalidated by teachers)
unsigned NumQstsNotBlank; // Number of questions not blank
bool Sent; // This exam print has been sent or not? bool Sent; // This exam print has been sent or not?
// "Sent" means that user has clicked "Send" button after finishing // "Sent" means that user has clicked "Send" button after finishing
double Score; // Total score of the exam print double Score; // Total score of the exam print

View File

@ -104,6 +104,7 @@ static void ExaRes_ShowResults (struct Exa_Exams *Exams,
const char *ExamsSelectedCommas); const char *ExamsSelectedCommas);
static void ExaRes_ShowResultsSummaryRow (unsigned NumResults, static void ExaRes_ShowResultsSummaryRow (unsigned NumResults,
unsigned NumTotalQsts, unsigned NumTotalQsts,
unsigned NumTotalQstsValid,
unsigned NumTotalQstsNotBlank, unsigned NumTotalQstsNotBlank,
double TotalScoreOfAllResults, double TotalScoreOfAllResults,
double TotalGrade); double TotalGrade);
@ -710,6 +711,7 @@ static void ExaRes_ShowHeaderResults (Usr_MeOrOther_t MeOrOther)
HTM_TH (1,1,"LT",Txt_START_END_TIME[Dat_END_TIME ]); HTM_TH (1,1,"LT",Txt_START_END_TIME[Dat_END_TIME ]);
HTM_TH (1,1,"LT",Txt_Session); HTM_TH (1,1,"LT",Txt_Session);
HTM_TH (1,1,"RT",Txt_Questions); HTM_TH (1,1,"RT",Txt_Questions);
HTM_TH (1,1,"RT","Preguntas v&aacute;lidas"); // TODO: Need translation!!!!
HTM_TH (1,1,"RT",Txt_Non_blank_BR_questions); HTM_TH (1,1,"RT",Txt_Non_blank_BR_questions);
HTM_TH (1,1,"RT",Txt_Score); HTM_TH (1,1,"RT",Txt_Score);
HTM_TH (1,1,"RT",Txt_Average_BR_score_BR_per_question_BR_from_0_to_1); HTM_TH (1,1,"RT",Txt_Average_BR_score_BR_per_question_BR_from_0_to_1);
@ -773,21 +775,22 @@ static void ExaRes_ShowResults (struct Exa_Exams *Exams,
unsigned NumResult; unsigned NumResult;
static unsigned UniqueId = 0; static unsigned UniqueId = 0;
char *Id; char *Id;
struct ExaPrn_Print Print;
struct ExaSes_Session Session; struct ExaSes_Session Session;
Dat_StartEndTime_t StartEndTime; Dat_StartEndTime_t StartEndTime;
unsigned NumQstsInThisResult;
unsigned NumQstsNotBlankInThisResult;
unsigned NumTotalQsts = 0; unsigned NumTotalQsts = 0;
unsigned NumTotalQstsValid = 0;
unsigned NumTotalQstsNotBlank = 0; unsigned NumTotalQstsNotBlank = 0;
double ScoreInThisResult;
double TotalScoreOfAllResults = 0.0; double TotalScoreOfAllResults = 0.0;
double TotalScoreValidOfAllResults = 0.0;
double MaxGrade; double MaxGrade;
double Grade; double Grade;
double TotalGrade = 0.0; double TotalGrade = 0.0;
unsigned Visibility; unsigned Visibility;
time_t TimeUTC[Dat_NUM_START_END_TIME]; time_t TimeUTC[Dat_NUM_START_END_TIME];
/***** Reset session *****/ /***** Reset print and session *****/
ExaPrn_ResetPrint (&Print);
ExaSes_ResetSession (&Session); ExaSes_ResetSession (&Session);
/***** Set user *****/ /***** Set user *****/
@ -854,14 +857,15 @@ static void ExaRes_ShowResults (struct Exa_Exams *Exams,
// must be able to access exams taken in other groups // must be able to access exams taken in other groups
NumResults = NumResults =
(unsigned) DB_QuerySELECT (&mysql_res,"can not get sessions results", (unsigned) DB_QuerySELECT (&mysql_res,"can not get sessions results",
"SELECT exa_prints.SesCod," // row[0] "SELECT exa_prints.PrnCod," // row[0]
"UNIX_TIMESTAMP(exa_prints.StartTime)," // row[1] "exa_prints.SesCod," // row[1]
"UNIX_TIMESTAMP(exa_prints.EndTime)," // row[2] "UNIX_TIMESTAMP(exa_prints.StartTime)," // row[2]
"exa_prints.NumQsts," // row[3] "UNIX_TIMESTAMP(exa_prints.EndTime)," // row[3]
"exa_prints.NumQstsNotBlank," // row[4] "exa_prints.NumQsts," // row[4]
"exa_prints.Score," // row[5] "exa_prints.NumQstsNotBlank," // row[5]
"exa_exams.MaxGrade," // row[6] "exa_prints.Score," // row[6]
"exa_exams.Visibility" // row[7] "exa_exams.MaxGrade," // row[7]
"exa_exams.Visibility" // row[8]
" FROM exa_prints,exa_sessions,exa_exams" " FROM exa_prints,exa_sessions,exa_exams"
" WHERE exa_prints.UsrCod=%ld" " WHERE exa_prints.UsrCod=%ld"
"%s" // Session subquery "%s" // Session subquery
@ -893,13 +897,17 @@ static void ExaRes_ShowResults (struct Exa_Exams *Exams,
{ {
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/* Get session code (row[0]) */ /* Get print code (row[0]) */
if ((Session.SesCod = Str_ConvertStrCodToLongCod (row[0])) < 0) if ((Print.PrnCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of exam print.");
/* Get session code (row[1]) */
if ((Session.SesCod = Str_ConvertStrCodToLongCod (row[1])) < 0)
Lay_ShowErrorAndExit ("Wrong code of session."); Lay_ShowErrorAndExit ("Wrong code of session.");
ExaSes_GetDataOfSessionByCod (&Session); ExaSes_GetDataOfSessionByCod (&Session);
/* Get visibility (row[7]) */ /* Get visibility (row[8]) */
Visibility = TstVis_GetVisibilityFromStr (row[7]); Visibility = TstVis_GetVisibilityFromStr (row[8]);
/* Show session result? */ /* Show session result? */
ICanViewResult = true; // Filtering is already made in the query ICanViewResult = true; // Filtering is already made in the query
@ -908,12 +916,12 @@ static void ExaRes_ShowResults (struct Exa_Exams *Exams,
if (NumResult) if (NumResult)
HTM_TR_Begin (NULL); HTM_TR_Begin (NULL);
/* Write start/end times (row[1], row[2] hold UTC start/end times) */ /* Write start/end times (row[2], row[3] hold UTC start/end times) */
for (StartEndTime = (Dat_StartEndTime_t) 0; for (StartEndTime = (Dat_StartEndTime_t) 0;
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1); StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
StartEndTime++) StartEndTime++)
{ {
TimeUTC[StartEndTime] = Dat_GetUNIXTimeFromStr (row[1 + StartEndTime]); TimeUTC[StartEndTime] = Dat_GetUNIXTimeFromStr (row[2 + StartEndTime]);
UniqueId++; UniqueId++;
if (asprintf (&Id,"exa_res_time_%u_%u",(unsigned) StartEndTime,UniqueId) < 0) if (asprintf (&Id,"exa_res_time_%u_%u",(unsigned) StartEndTime,UniqueId) < 0)
Lay_NotEnoughMemoryExit (); Lay_NotEnoughMemoryExit ();
@ -933,25 +941,29 @@ static void ExaRes_ShowResults (struct Exa_Exams *Exams,
if (ICanViewScore) if (ICanViewScore)
{ {
/* Get number of questions (row[3]) */ /* Get questions and user's answers of exam print from database */
if (sscanf (row[3],"%u",&NumQstsInThisResult) != 1) ExaPrn_GetPrintQuestionsFromDB (&Print);
NumQstsInThisResult = 0; NumTotalQsts += Print.NumQsts;
NumTotalQsts += NumQstsInThisResult;
/* Get number of questions not blank (row[4]) */ /* Compute score taking into account only valid questions */
if (sscanf (row[4],"%u",&NumQstsNotBlankInThisResult) != 1) ExaRes_ComputeScoreValid (&Print);
NumQstsNotBlankInThisResult = 0; NumTotalQstsValid += Print.NumQstsValid;
NumTotalQstsNotBlank += NumQstsNotBlankInThisResult; TotalScoreValidOfAllResults += Print.ScoreValid;
/* Get number of questions not blank (row[5]) */
if (sscanf (row[5],"%u",&Print.NumQstsNotBlank) != 1)
Print.NumQstsNotBlank = 0;
NumTotalQstsNotBlank += Print.NumQstsNotBlank;
Str_SetDecimalPointToUS (); // To get the decimal point as a dot Str_SetDecimalPointToUS (); // To get the decimal point as a dot
/* Get score (row[5]) */ /* Get score (row[6]) */
if (sscanf (row[5],"%lf",&ScoreInThisResult) != 1) if (sscanf (row[6],"%lf",&Print.Score) != 1)
ScoreInThisResult = 0.0; Print.Score = 0.0;
TotalScoreOfAllResults += ScoreInThisResult; TotalScoreOfAllResults += Print.Score;
/* Get maximum grade (row[6]) */ /* Get maximum grade (row[7]) */
if (sscanf (row[6],"%lf",&MaxGrade) != 1) if (sscanf (row[7],"%lf",&MaxGrade) != 1)
MaxGrade = 0.0; MaxGrade = 0.0;
Str_SetDecimalPointToLocal (); // Return to local system Str_SetDecimalPointToLocal (); // Return to local system
@ -960,7 +972,15 @@ static void ExaRes_ShowResults (struct Exa_Exams *Exams,
/* Write number of questions */ /* Write number of questions */
HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd);
if (ICanViewScore) if (ICanViewScore)
HTM_Unsigned (NumQstsInThisResult); HTM_Unsigned (Print.NumQsts);
else
Ico_PutIconNotVisible ();
HTM_TD_End ();
/* Write number of valid questions */
HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd);
if (ICanViewScore)
HTM_Unsigned (Print.NumQstsValid);
else else
Ico_PutIconNotVisible (); Ico_PutIconNotVisible ();
HTM_TD_End (); HTM_TD_End ();
@ -968,34 +988,34 @@ static void ExaRes_ShowResults (struct Exa_Exams *Exams,
/* Write number of questions not blank */ /* Write number of questions not blank */
HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd);
if (ICanViewScore) if (ICanViewScore)
HTM_Unsigned (NumQstsNotBlankInThisResult); HTM_Unsigned (Print.NumQstsNotBlank);
else else
Ico_PutIconNotVisible (); Ico_PutIconNotVisible ();
HTM_TD_End (); HTM_TD_End ();
/* Write score */ /* Write score valid (taking into account only valid questions) */
HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd);
if (ICanViewScore) if (ICanViewScore)
HTM_Double2Decimals (ScoreInThisResult); HTM_Double2Decimals (Print.ScoreValid);
else else
Ico_PutIconNotVisible (); Ico_PutIconNotVisible ();
HTM_TD_End (); HTM_TD_End ();
/* Write average score per question */ /* Write average score per question (taking into account only valid questions) */
HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd);
if (ICanViewScore) if (ICanViewScore)
HTM_Double2Decimals (NumQstsInThisResult ? ScoreInThisResult / HTM_Double2Decimals (Print.NumQstsValid ? Print.ScoreValid /
(double) NumQstsInThisResult : (double) Print.NumQstsValid :
0.0); 0.0);
else else
Ico_PutIconNotVisible (); Ico_PutIconNotVisible ();
HTM_TD_End (); HTM_TD_End ();
/* Write grade over maximum grade */ /* Write grade over maximum grade (taking into account only valid questions) */
HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd);
if (ICanViewScore) if (ICanViewScore)
{ {
Grade = TstPrn_ComputeGrade (NumQstsInThisResult,ScoreInThisResult,MaxGrade); Grade = TstPrn_ComputeGrade (Print.NumQstsValid,Print.ScoreValid,MaxGrade);
TstPrn_ShowGrade (Grade,MaxGrade); TstPrn_ShowGrade (Grade,MaxGrade);
TotalGrade += Grade; TotalGrade += Grade;
} }
@ -1032,10 +1052,14 @@ static void ExaRes_ShowResults (struct Exa_Exams *Exams,
} }
/***** Write totals for this user *****/ /***** Write totals for this user *****/
// ExaRes_ShowResultsSummaryRow (NumResults,
// NumTotalQsts,NumTotalQstsNotBlank,
// TotalScoreOfAllResults,
// TotalGrade);
ExaRes_ShowResultsSummaryRow (NumResults, ExaRes_ShowResultsSummaryRow (NumResults,
NumTotalQsts,NumTotalQstsNotBlank, NumTotalQsts,NumTotalQstsValid,NumTotalQstsNotBlank,
TotalScoreOfAllResults, TotalScoreValidOfAllResults,
TotalGrade); TotalGrade);
} }
else else
{ {
@ -1055,6 +1079,7 @@ static void ExaRes_ShowResults (struct Exa_Exams *Exams,
static void ExaRes_ShowResultsSummaryRow (unsigned NumResults, static void ExaRes_ShowResultsSummaryRow (unsigned NumResults,
unsigned NumTotalQsts, unsigned NumTotalQsts,
unsigned NumTotalQstsValid,
unsigned NumTotalQstsNotBlank, unsigned NumTotalQstsNotBlank,
double TotalScoreOfAllResults, double TotalScoreOfAllResults,
double TotalGrade) double TotalGrade)
@ -1076,6 +1101,12 @@ static void ExaRes_ShowResultsSummaryRow (unsigned NumResults,
HTM_Unsigned (NumTotalQsts); HTM_Unsigned (NumTotalQsts);
HTM_TD_End (); HTM_TD_End ();
/***** Write total number of questions valid *****/
HTM_TD_Begin ("class=\"DAT_N_LINE_TOP RM COLOR%u\"",Gbl.RowEvenOdd);
if (NumResults)
HTM_Unsigned (NumTotalQstsValid);
HTM_TD_End ();
/***** Write total number of questions not blank *****/ /***** Write total number of questions not blank *****/
HTM_TD_Begin ("class=\"DAT_N_LINE_TOP RM COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT_N_LINE_TOP RM COLOR%u\"",Gbl.RowEvenOdd);
if (NumResults) if (NumResults)
@ -1475,8 +1506,11 @@ static bool ExaRes_CheckIfICanViewScore (bool ICanViewResult,unsigned Visibility
static void ExaRes_ComputeScoreValid (struct ExaPrn_Print *Print) static void ExaRes_ComputeScoreValid (struct ExaPrn_Print *Print)
{ {
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumQst; unsigned NumQst;
struct Tst_Question Question; struct Tst_Question Question;
bool QuestionExists;
/***** Initialize score valid *****/ /***** Initialize score valid *****/
Print->NumQstsValid = 0; Print->NumQstsValid = 0;
@ -1486,25 +1520,39 @@ static void ExaRes_ComputeScoreValid (struct ExaPrn_Print *Print)
NumQst < Print->NumQsts; NumQst < Print->NumQsts;
NumQst++) NumQst++)
{ {
Gbl.RowEvenOdd = NumQst % 2; /***** Copy question code *****/
/***** Create test question *****/
Tst_QstConstructor (&Question);
Question.QstCod = Print->PrintedQuestions[NumQst].QstCod; Question.QstCod = Print->PrintedQuestions[NumQst].QstCod;
/***** Get question data *****/ /***** Get validity and answer type from database *****/
ExaSet_GetQstDataFromDB (&Question); QuestionExists = (DB_QuerySELECT (&mysql_res,"can not get a question",
"SELECT Invalid," // row[0]
/***** Compute answer score *****/ "AnsType" // row[1]
if (Question.Validity == Tst_VALID_QUESTION) " FROM exa_set_questions"
" WHERE QstCod=%ld",
Question.QstCod) != 0);
if (QuestionExists)
{ {
ExaPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question); row = mysql_fetch_row (mysql_res);
Print->NumQstsValid++;
Print->ScoreValid += Print->PrintedQuestions[NumQst].Score; /* Get whether the question is invalid (row[0]) */
Question.Validity = (row[0][0] == 'Y') ? Tst_INVALID_QUESTION :
Tst_VALID_QUESTION;
/* Get the type of answer (row[1]) */
Question.Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
} }
/***** Destroy test question *****/ /* Free structure that stores the query result */
Tst_QstDestructor (&Question); DB_FreeMySQLResult (&mysql_res);
/***** Compute answer score *****/
if (QuestionExists)
if (Question.Validity == Tst_VALID_QUESTION)
{
ExaPrn_ComputeAnswerScore (&Print->PrintedQuestions[NumQst],&Question);
Print->NumQstsValid++;
Print->ScoreValid += Print->PrintedQuestions[NumQst].Score;
}
} }
} }