Version19.157

This commit is contained in:
acanas 2020-04-01 03:11:05 +02:00
parent 2603e5a906
commit d8233a0aa8
10 changed files with 1396 additions and 928 deletions

View File

@ -13250,6 +13250,7 @@ INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2010; Hecho
INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2011; Hecho INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2011; Hecho
INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2012; Hecho INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2012; Hecho
INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2013; Hecho INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2013; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140101' AND ClickTime<'20140201'; Hecho INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140101' AND ClickTime<'20140201'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140201' AND ClickTime<'20140301'; Hecho INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140201' AND ClickTime<'20140301'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140301' AND ClickTime<'20140401'; Hecho INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140301' AND ClickTime<'20140401'; Hecho
@ -13259,13 +13260,38 @@ INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140601' AND ClickTime
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140701' AND ClickTime<'20140801'; Hecho INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140701' AND ClickTime<'20140801'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140801' AND ClickTime<'20140901'; Hecho INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140801' AND ClickTime<'20140901'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140901' AND ClickTime<'20141001'; Hecho INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20140901' AND ClickTime<'20141001'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20141001' AND ClickTime<'20141101'; INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20141001' AND ClickTime<'20141101'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20141101' AND ClickTime<'20141201'; INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20141101' AND ClickTime<'20141201'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20141201' AND ClickTime<'20150101'; INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20141201' AND ClickTime<'20150101'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2015;
INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2016; INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20150101' AND ClickTime<'20150201'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2017; INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20150201' AND ClickTime<'20150301'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2018; INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20150301' AND ClickTime<'20150401'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20150401' AND ClickTime<'20150501'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20150501' AND ClickTime<'20150601'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20150601' AND ClickTime<'20150701'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20150701' AND ClickTime<'20150801'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20150801' AND ClickTime<'20150901'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20150901' AND ClickTime<'20151001'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20151001' AND ClickTime<'20151101'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20151101' AND ClickTime<'20151201'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20151201' AND ClickTime<'20160101'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20160101' AND ClickTime<'20160201'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20160201' AND ClickTime<'20160301'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20160301' AND ClickTime<'20160401'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20160401' AND ClickTime<'20160501'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20160501' AND ClickTime<'20160601'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20160601' AND ClickTime<'20160701'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20160701' AND ClickTime<'20160801'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20160801' AND ClickTime<'20160901'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20160901' AND ClickTime<'20161001'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20161001' AND ClickTime<'20161101'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20161101' AND ClickTime<'20161201'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE ClickTime>='20161201' AND ClickTime<'20170101'; Hecho
INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2017; Hecho
INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2018; Hecho
INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2019; INSERT INTO log SELECT * FROM log_full WHERE YEAR(ClickTime) = 2019;
# hasta aquí ya hecho en openswad.org, aún no en swad.ugr.es # hasta aquí ya hecho en openswad.org, aún no en swad.ugr.es

View File

@ -4,20 +4,16 @@
SWAD (Shared Workspace At a Distance), SWAD (Shared Workspace At a Distance),
is a web platform developed at the University of Granada (Spain), is a web platform developed at the University of Granada (Spain),
and used to support university teaching. and used to support university teaching.
This file is part of SWAD core. This file is part of SWAD core.
Copyright (C) 1999-2020 Antonio Cañas Vargas Copyright (C) 1999-2020 Antonio Cañas Vargas
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version. License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details. GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */

View File

@ -497,7 +497,7 @@ 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.156.4 (2020-03-29)" #define Log_PLATFORM_VERSION "SWAD 19.157 (2020-04-01)"
#define CSS_FILE "swad19.146.css" #define CSS_FILE "swad19.146.css"
#define JS_FILE "swad19.153.js" #define JS_FILE "swad19.153.js"
/* /*
@ -528,7 +528,8 @@ Param
El examen se muestra en pantalla tomándolo del examen en la base de datos, no del formulario. El examen se muestra en pantalla tomándolo del examen en la base de datos, no del formulario.
Cuando el alumno pulsa en "He terminado" se le pregunta si está seguro y se vuelve a mostrar el examen cogiéndolo de la base de datos. Cuando el alumno pulsa en "He terminado" se le pregunta si está seguro y se vuelve a mostrar el examen cogiéndolo de la base de datos.
Version 19.156.5: Mar 29, 2020 Test exam is stored in database when it's generated. (? lines) Version 19.157: Apr 01, 2020 Code refactoring in tests.
Test exam is stored in database when it's generated. Not tested. (285023 lines)
Version 19.156.4: Mar 29, 2020 Code refactoring in tests. (284657 lines) Version 19.156.4: Mar 29, 2020 Code refactoring in tests. (284657 lines)
Version 19.156.3: Mar 29, 2020 Code refactoring in tests. (284585 lines) Version 19.156.3: Mar 29, 2020 Code refactoring in tests. (284585 lines)
Version 19.156.2: Mar 29, 2020 Test exam with start date and end date. (284568 lines) Version 19.156.2: Mar 29, 2020 Test exam with start date and end date. (284568 lines)

View File

@ -3956,10 +3956,6 @@ static void Mch_ComputeScore (struct TsR_Result *Result)
{ {
unsigned NumQst; unsigned NumQst;
struct Tst_Question Question; struct Tst_Question Question;
double ScoreThisQst;
bool AnswerIsNotBlank;
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION];
for (NumQst = 0, Result->Score = 0.0; for (NumQst = 0, Result->Score = 0.0;
NumQst < Result->NumQsts; NumQst < Result->NumQsts;
@ -3967,20 +3963,14 @@ static void Mch_ComputeScore (struct TsR_Result *Result)
{ {
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question); Tst_QstConstructor (&Question);
Question.QstCod = Result->QstCodes[NumQst]; Question.QstCod = Result->Questions[NumQst].QstCod;
Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE; Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE;
/***** Get correct answers of test question from database *****/ /***** Compute score for this answer ******/
Tst_GetCorrectAnswersFromDB (&Question); Tst_ComputeChoiceAnsScore (Result,NumQst,&Question);
/***** Compute the score of this question *****/
Tst_GetIndexesFromStr (Result->StrIndexes[NumQst],Indexes);
Tst_GetAnswersFromStr (Result->StrAnswers[NumQst],AnswersUsr);
Tst_ComputeScoreQst (&Question,
Indexes,AnswersUsr,&ScoreThisQst,&AnswerIsNotBlank);
/***** Update total score *****/ /***** Update total score *****/
Result->Score += ScoreThisQst; Result->Score += Result->Questions[NumQst].Score;
/***** Destroy test question *****/ /***** Destroy test question *****/
Tst_QstDestructor (&Question); Tst_QstDestructor (&Question);

View File

@ -1251,7 +1251,7 @@ void McR_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod,
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/* Get question code (row[0]) */ /* Get question code (row[0]) */
if ((Result->QstCodes[NumQst] = Str_ConvertStrCodToLongCod (row[0])) < 0) if ((Result->Questions[NumQst].QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of question."); Lay_ShowErrorAndExit ("Wrong code of question.");
/* Get question index (row[1]) */ /* Get question index (row[1]) */
@ -1260,24 +1260,24 @@ void McR_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod,
QstInd = (unsigned) LongNum; QstInd = (unsigned) LongNum;
/* Get indexes for this question (row[2]) */ /* Get indexes for this question (row[2]) */
Str_Copy (Result->StrIndexes[NumQst],row[2], Str_Copy (Result->Questions[NumQst].StrIndexes,row[2],
Tst_MAX_BYTES_INDEXES_ONE_QST); Tst_MAX_BYTES_INDEXES_ONE_QST);
/* Get answers selected by user for this question */ /* Get answers selected by user for this question */
Mch_GetQstAnsFromDB (MchCod,UsrCod,QstInd,&UsrAnswer); Mch_GetQstAnsFromDB (MchCod,UsrCod,QstInd,&UsrAnswer);
if (UsrAnswer.AnsInd >= 0) // UsrAnswer.AnsInd >= 0 ==> answer selected if (UsrAnswer.AnsInd >= 0) // UsrAnswer.AnsInd >= 0 ==> answer selected
{ {
snprintf (Result->StrAnswers[NumQst],Tst_MAX_BYTES_ANSWERS_ONE_QST + 1, snprintf (Result->Questions[NumQst].StrAnswers,Tst_MAX_BYTES_ANSWERS_ONE_QST + 1,
"%d",UsrAnswer.AnsInd); "%d",UsrAnswer.AnsInd);
Result->NumQstsNotBlank++; Result->NumQstsNotBlank++;
} }
else // UsrAnswer.AnsInd < 0 ==> no answer selected else // UsrAnswer.AnsInd < 0 ==> no answer selected
Result->StrAnswers[NumQst][0] = '\0'; // Empty answer Result->Questions[NumQst].StrAnswers[0] = '\0'; // Empty answer
/* Replace each comma by a separator of multiple parameters */ /* Replace each comma by a separator of multiple parameters */
/* In database commas are used as separators instead of special chars */ /* In database commas are used as separators instead of special chars */
Par_ReplaceCommaBySeparatorMultiple (Result->StrIndexes[NumQst]); Par_ReplaceCommaBySeparatorMultiple (Result->Questions[NumQst].StrIndexes);
Par_ReplaceCommaBySeparatorMultiple (Result->StrAnswers[NumQst]); Par_ReplaceCommaBySeparatorMultiple (Result->Questions[NumQst].StrAnswers);
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/

View File

@ -267,7 +267,7 @@ void Med_GetMediaDataByCod (struct Media *Media)
size_t Length; size_t Length;
/***** Get data of a media from database *****/ /***** Get data of a media from database *****/
NumRows = DB_QuerySELECT (&mysql_res,"can not get data of a post", NumRows = DB_QuerySELECT (&mysql_res,"can not get media",
"SELECT Type," // row[0] "SELECT Type," // row[0]
"Name," // row[1] "Name," // row[1]
"URL," // row[2] "URL," // row[2]

File diff suppressed because it is too large Load Diff

View File

@ -155,6 +155,12 @@ void Tst_ShowNewTest (void);
void Tst_RequestAssessTest (void); void Tst_RequestAssessTest (void);
void Tst_AssessTest (void); void Tst_AssessTest (void);
void Tst_ComputeChoiceAnsScore (struct TsR_Result *Result,
unsigned NumQst,
struct Tst_Question *Question);
void Tst_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc.
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]);
void Tst_ComputeAndShowGrade (unsigned NumQsts,double Score,double MaxGrade); void Tst_ComputeAndShowGrade (unsigned NumQsts,double Score,double MaxGrade);
double Tst_ComputeGrade (unsigned NumQsts,double Score,double MaxGrade); double Tst_ComputeGrade (unsigned NumQsts,double Score,double MaxGrade);
void Tst_ShowGrade (double Grade,double MaxGrade); void Tst_ShowGrade (double Grade,double MaxGrade);
@ -162,11 +168,10 @@ void Tst_ShowGrade (double Grade,double MaxGrade);
void Tst_ShowTagList (unsigned NumTags,MYSQL_RES *mysql_res); void Tst_ShowTagList (unsigned NumTags,MYSQL_RES *mysql_res);
void Tst_WriteQstAndAnsTestResult (struct UsrData *UsrDat, void Tst_WriteQstAndAnsTestResult (struct UsrData *UsrDat,
const struct TsR_Result *Result, struct TsR_Result *Result,
unsigned NumQst, unsigned NumQst,
MYSQL_ROW row, MYSQL_ROW row,
unsigned Visibility, unsigned Visibility);
double *ScoreThisQst,bool *AnswerIsNotBlank);
void Tst_WriteNumQst (unsigned NumQst); void Tst_WriteNumQst (unsigned NumQst);
void Tst_WriteAnswerType (Tst_AnswerType_t AnswerType); void Tst_WriteAnswerType (Tst_AnswerType_t AnswerType);
void Tst_WriteQstStem (const char *Stem,const char *ClassStem,bool Visible); void Tst_WriteQstStem (const char *Stem,const char *ClassStem,bool Visible);
@ -183,18 +188,9 @@ void Tst_WriteParamEditQst (const struct Tst_Test *Test);
unsigned Tst_GetNumAnswersQst (long QstCod); unsigned Tst_GetNumAnswersQst (long QstCod);
void Tst_GetAnswersQst (struct Tst_Question *Question,MYSQL_RES **mysql_res, void Tst_GetAnswersQst (struct Tst_Question *Question,MYSQL_RES **mysql_res,
bool Shuffle); bool Shuffle);
void Tst_GetCorrectAnswersFromDB (struct Tst_Question *Question);
void Tst_WriteAnswersListing (struct Tst_Question *Question); void Tst_WriteAnswersListing (struct Tst_Question *Question);
bool Tst_CheckIfQuestionIsValidForGame (long QstCod); bool Tst_CheckIfQuestionIsValidForGame (long QstCod);
void Tst_WriteAnsTF (char AnsTF); void Tst_WriteAnsTF (char AnsTF);
void Tst_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc.
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]);
void Tst_GetAnswersFromStr (const char StrAnswersOneQst[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1],
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION]);
void Tst_ComputeScoreQst (const struct Tst_Question *Question,
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION],
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION],
double *ScoreThisQst,bool *AnswerIsNotBlank);
void Tst_CheckIfNumberOfAnswersIsOne (const struct Tst_Question *Question); void Tst_CheckIfNumberOfAnswersIsOne (const struct Tst_Question *Question);
unsigned long Tst_GetTagsQst (long QstCod,MYSQL_RES **mysql_res); unsigned long Tst_GetTagsQst (long QstCod,MYSQL_RES **mysql_res);

View File

@ -168,13 +168,13 @@ void TsR_ShowMyTstResults (void)
} }
/*****************************************************************************/ /*****************************************************************************/
/********************* Store test result in database *************************/ /**************** Create new blank test result in database *******************/
/*****************************************************************************/ /*****************************************************************************/
long TsR_CreateTestResultInDB (const struct TsR_Result *Result) void TsR_CreateTestResultInDB (struct TsR_Result *Result)
{ {
/***** Insert new test result into table *****/ /***** Insert new test result into table *****/
return Result->TstCod =
DB_QueryINSERTandReturnCode ("can not create new test result", DB_QueryINSERTandReturnCode ("can not create new test result",
"INSERT INTO tst_exams" "INSERT INTO tst_exams"
" (CrsCod,UsrCod,StartTime,EndTime,NumQsts,AllowTeachers)" " (CrsCod,UsrCod,StartTime,EndTime,NumQsts,AllowTeachers)"
@ -191,19 +191,22 @@ long TsR_CreateTestResultInDB (const struct TsR_Result *Result)
/********************* Store test result in database *************************/ /********************* Store test result in database *************************/
/*****************************************************************************/ /*****************************************************************************/
void TsR_StoreScoreOfTestResultInDB (long TstCod, void TsR_UpdateScoreOfTestResultInDB (const struct TsR_Result *Result)
const struct TsR_Result *Result)
{ {
/***** Update score in test result *****/ /***** Update score in test result *****/
Str_SetDecimalPointToUS (); // To print the floating point as a dot Str_SetDecimalPointToUS (); // To print the floating point as a dot
DB_QueryUPDATE ("can not update test result", DB_QueryUPDATE ("can not update test result",
"UPDATE tst_exams" "UPDATE tst_exams"
" SET NumQstsNotBlank=%u," " SET EndTime=NOW(),"
"NumQstsNotBlank=%u,"
"Score='%.15lg'" "Score='%.15lg'"
" WHERE TstCod=%ld", " WHERE TstCod=%ld"
" AND CrsCod=%ld AND UsrCod=%ld", // Extra checks
Result->NumQstsNotBlank, Result->NumQstsNotBlank,
Result->Score, Result->Score,
TstCod); Result->TstCod,
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Usrs.Me.UsrDat.UsrCod);
Str_SetDecimalPointToLocal (); // Return to local system Str_SetDecimalPointToLocal (); // Return to local system
} }
@ -847,7 +850,7 @@ void TsR_ShowOneTstResult (void)
static void TsR_ShowTstTagsPresentInATestResult (long TstCod) static void TsR_ShowTstTagsPresentInATestResult (long TstCod)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
unsigned long NumTags; unsigned NumTags;
/***** Get all tags of questions in this test *****/ /***** Get all tags of questions in this test *****/
NumTags = (unsigned) NumTags = (unsigned)
@ -874,7 +877,7 @@ static void TsR_ShowTstTagsPresentInATestResult (long TstCod)
/*****************************************************************************/ /*****************************************************************************/
void TsR_ShowTestResult (struct UsrData *UsrDat, void TsR_ShowTestResult (struct UsrData *UsrDat,
const struct TsR_Result *Result, struct TsR_Result *Result,
unsigned Visibility) unsigned Visibility)
{ {
extern const char *Txt_Question_modified; extern const char *Txt_Question_modified;
@ -882,8 +885,6 @@ void TsR_ShowTestResult (struct UsrData *UsrDat,
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
unsigned NumQst; unsigned NumQst;
double ScoreThisQst;
bool AnswerIsNotBlank;
bool ThisQuestionHasBeenEdited; bool ThisQuestionHasBeenEdited;
time_t EditTimeUTC; time_t EditTimeUTC;
@ -894,7 +895,7 @@ void TsR_ShowTestResult (struct UsrData *UsrDat,
Gbl.RowEvenOdd = NumQst % 2; Gbl.RowEvenOdd = NumQst % 2;
/***** Query database *****/ /***** Query database *****/
if (Tst_GetOneQuestionByCod (Result->QstCodes[NumQst],&mysql_res)) // Question exists if (Tst_GetOneQuestionByCod (Result->Questions[NumQst].QstCod,&mysql_res)) // Question exists
{ {
/***** Get row of the result of the query *****/ /***** Get row of the result of the query *****/
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
@ -927,9 +928,7 @@ void TsR_ShowTestResult (struct UsrData *UsrDat,
Result, Result,
NumQst, NumQst,
row, row,
Visibility, Visibility);
&ScoreThisQst, // Not used here
&AnswerIsNotBlank); // Not used here
} }
else else
{ {
@ -1020,17 +1019,16 @@ static void TsR_GetTestResultDataByTstCod (long TstCod,struct TsR_Result *Result
/************ Store user's answers of an test result into database ***********/ /************ Store user's answers of an test result into database ***********/
/*****************************************************************************/ /*****************************************************************************/
void TsR_StoreOneTestResultQstInDB (long TstCod, void TsR_StoreOneTestResultQstInDB (const struct TsR_Result *Result,
const struct TsR_Result *Result, unsigned NumQst)
unsigned NumQst,double ScoreThisQst)
{ {
char Indexes[Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; char StrIndexes[Tst_MAX_BYTES_INDEXES_ONE_QST + 1];
char Answers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; char StrAnswers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1];
/***** Replace each separator of multiple parameters by a comma *****/ /***** Replace each separator of multiple parameters by a comma *****/
/* In database commas are used as separators instead of special chars */ /* In database commas are used as separators instead of special chars */
Par_ReplaceSeparatorMultipleByComma (Result->StrIndexes[NumQst],Indexes); Par_ReplaceSeparatorMultipleByComma (Result->Questions[NumQst].StrIndexes,StrIndexes);
Par_ReplaceSeparatorMultipleByComma (Result->StrAnswers[NumQst],Answers); Par_ReplaceSeparatorMultipleByComma (Result->Questions[NumQst].StrAnswers,StrAnswers);
/***** Insert question and user's answers into database *****/ /***** Insert question and user's answers into database *****/
Str_SetDecimalPointToUS (); // To print the floating point as a dot Str_SetDecimalPointToUS (); // To print the floating point as a dot
@ -1039,11 +1037,11 @@ void TsR_StoreOneTestResultQstInDB (long TstCod,
" (TstCod,QstCod,QstInd,Score,Indexes,Answers)" " (TstCod,QstCod,QstInd,Score,Indexes,Answers)"
" VALUES" " VALUES"
" (%ld,%ld,%u,'%.15lg','%s','%s')", " (%ld,%ld,%u,'%.15lg','%s','%s')",
TstCod,Result->QstCodes[NumQst], Result->TstCod,Result->Questions[NumQst].QstCod,
NumQst, // 0, 1, 2, 3... NumQst, // 0, 1, 2, 3...
ScoreThisQst, Result->Questions[NumQst].Score,
Indexes, StrIndexes,
Answers); StrAnswers);
Str_SetDecimalPointToLocal (); // Return to local system Str_SetDecimalPointToLocal (); // Return to local system
} }
@ -1077,21 +1075,21 @@ static void TsR_GetTestResultQuestionsFromDB (long TstCod,struct TsR_Result *Res
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/* Get question code */ /* Get question code */
if ((Result->QstCodes[NumQst] = Str_ConvertStrCodToLongCod (row[0])) < 0) if ((Result->Questions[NumQst].QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of question."); Lay_ShowErrorAndExit ("Wrong code of question.");
/* Get indexes for this question (row[1]) */ /* Get indexes for this question (row[1]) */
Str_Copy (Result->StrIndexes[NumQst],row[1], Str_Copy (Result->Questions[NumQst].StrIndexes,row[1],
Tst_MAX_BYTES_INDEXES_ONE_QST); Tst_MAX_BYTES_INDEXES_ONE_QST);
/* Get answers selected by user for this question (row[2]) */ /* Get answers selected by user for this question (row[2]) */
Str_Copy (Result->StrAnswers[NumQst],row[2], Str_Copy (Result->Questions[NumQst].StrAnswers,row[2],
Tst_MAX_BYTES_ANSWERS_ONE_QST); Tst_MAX_BYTES_ANSWERS_ONE_QST);
/* Replace each comma by a separator of multiple parameters */ /* Replace each comma by a separator of multiple parameters */
/* In database commas are used as separators instead of special chars */ /* In database commas are used as separators instead of special chars */
Par_ReplaceCommaBySeparatorMultiple (Result->StrIndexes[NumQst]); Par_ReplaceCommaBySeparatorMultiple (Result->Questions[NumQst].StrIndexes);
Par_ReplaceCommaBySeparatorMultiple (Result->StrAnswers[NumQst]); Par_ReplaceCommaBySeparatorMultiple (Result->Questions[NumQst].StrAnswers);
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/

View File

@ -45,16 +45,20 @@
struct TsR_Result struct TsR_Result
{ {
long TstCod; // Exam code
time_t TimeUTC[Dat_NUM_START_END_TIME]; time_t TimeUTC[Dat_NUM_START_END_TIME];
unsigned NumQsts; unsigned NumQsts; // Number of questions
unsigned NumQstsNotBlank; unsigned NumQstsNotBlank; // Number of questions not blank
long QstCodes[TstCfg_MAX_QUESTIONS_PER_TEST]; // Codes of the sent/received questions in a test bool AllowTeachers; // Are teachers allowed to see this test result?
char StrIndexes[TstCfg_MAX_QUESTIONS_PER_TEST] double Score; // Total score of the test result
[Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; // 0 1 2 3, 3 0 2 1, etc. struct
char StrAnswers[TstCfg_MAX_QUESTIONS_PER_TEST] {
[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user long QstCod; // Question code
bool AllowTeachers; // Are teachers allowed to see this test result? char StrIndexes[Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; // 0 1 2 3, 3 0 2 1, etc.
double Score; // Total score of the test result char StrAnswers[Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user
double Score; // Question score
bool AnswerIsNotBlank; // Answer not blank?
} Questions[TstCfg_MAX_QUESTIONS_PER_TEST];
}; };
/*****************************************************************************/ /*****************************************************************************/
@ -64,17 +68,15 @@ struct TsR_Result
void TsR_SelUsrsToViewUsrsTstResults (void); void TsR_SelUsrsToViewUsrsTstResults (void);
void TsR_SelDatesToSeeMyTstResults (void); void TsR_SelDatesToSeeMyTstResults (void);
void TsR_ShowMyTstResults (void); void TsR_ShowMyTstResults (void);
long TsR_CreateTestResultInDB (const struct TsR_Result *Result); void TsR_CreateTestResultInDB (struct TsR_Result *Result);
void TsR_StoreScoreOfTestResultInDB (long TstCod, void TsR_UpdateScoreOfTestResultInDB (const struct TsR_Result *Result);
const struct TsR_Result *Result);
void TsR_GetUsrsAndShowTstResults (void); void TsR_GetUsrsAndShowTstResults (void);
void TsR_ShowOneTstResult (void); void TsR_ShowOneTstResult (void);
void TsR_ShowTestResult (struct UsrData *UsrDat, void TsR_ShowTestResult (struct UsrData *UsrDat,
const struct TsR_Result *Result, struct TsR_Result *Result,
unsigned Visibility); unsigned Visibility);
void TsR_StoreOneTestResultQstInDB (long TstCod, void TsR_StoreOneTestResultQstInDB (const struct TsR_Result *Result,
const struct TsR_Result *Result, unsigned NumQst);
unsigned NumQst,double ScoreThisQst);
void TsR_RemoveTestResultsMadeByUsrInAllCrss (long UsrCod); void TsR_RemoveTestResultsMadeByUsrInAllCrss (long UsrCod);
void TsR_RemoveTestResultsMadeByUsrInCrs (long UsrCod,long CrsCod); void TsR_RemoveTestResultsMadeByUsrInCrs (long UsrCod,long CrsCod);
void TsR_RemoveCrsTestResults (long CrsCod); void TsR_RemoveCrsTestResults (long CrsCod);