Version19.154

This commit is contained in:
acanas 2020-03-25 01:36:22 +01:00
parent 01f4e74c7f
commit 07ebc6aef4
6 changed files with 416 additions and 468 deletions

View File

@ -497,13 +497,13 @@ 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.153 (2020-03-24)" #define Log_PLATFORM_VERSION "SWAD 19.154 (2020-03-25)"
#define CSS_FILE "swad19.146.css" #define CSS_FILE "swad19.146.css"
#define JS_FILE "swad19.153.js" #define JS_FILE "swad19.153.js"
/* /*
* *
// TODO: Geolocalización: // TODO: Geolocalización:
Función API sendLocation... Función API sendCurrentLocation...
Parámetros: string con ubicación (ej. "Aula 0.1") Parámetros: string con ubicación (ej. "Aula 0.1")
Poblar base de datos: Poblar base de datos:
@ -524,6 +524,7 @@ Param
// TODO: Oresti Baños: cambiar ojos por candados en descriptores para prohibir/permitir y dejar los ojos para poder elegir descriptores // TODO: Oresti Baños: cambiar ojos por candados en descriptores para prohibir/permitir y dejar los ojos para poder elegir descriptores
// TODO: Si el alumno ha marcado "Permitir que los profesores...", entonces pedir confirmación al pulsar el botón azul, para evitar que se envíe por error antes de tiempo // TODO: Si el alumno ha marcado "Permitir que los profesores...", entonces pedir confirmación al pulsar el botón azul, para evitar que se envíe por error antes de tiempo
Version 19.154: Mar 25, 2020 Code refactoring in tests. (283385 lines)
Version 19.153: Mar 24, 2020 Code refactoring in tests. (283432 lines) Version 19.153: Mar 24, 2020 Code refactoring in tests. (283432 lines)
Version 19.152.4: Mar 24, 2020 Code refactoring in tests. (283459 lines) Version 19.152.4: Mar 24, 2020 Code refactoring in tests. (283459 lines)
Version 19.152.3: Mar 23, 2020 Code refactoring in tests. (283512 lines) Version 19.152.3: Mar 23, 2020 Code refactoring in tests. (283512 lines)

View File

@ -156,7 +156,8 @@ static void Gam_ListGameQuestions (struct Game *Game);
static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
MYSQL_RES *mysql_res, MYSQL_RES *mysql_res,
bool ICanEditQuestions); bool ICanEditQuestions);
static void Gam_ListQuestionForEdition (long QstCod,unsigned QstInd); static void Gam_ListQuestionForEdition (struct Tst_Question *Question,
unsigned QstInd);
static void Gam_PutIconToAddNewQuestions (void); static void Gam_PutIconToAddNewQuestions (void);
static void Gam_PutButtonToAddNewQuestions (void); static void Gam_PutButtonToAddNewQuestions (void);
@ -1873,7 +1874,6 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
extern const char *Txt_Movement_not_allowed; extern const char *Txt_Movement_not_allowed;
unsigned NumQst; unsigned NumQst;
MYSQL_ROW row; MYSQL_ROW row;
long QstCod;
struct Tst_Question Question; struct Tst_Question Question;
unsigned QstInd; unsigned QstInd;
unsigned MaxQstInd; unsigned MaxQstInd;
@ -1902,13 +1902,15 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
{ {
Gbl.RowEvenOdd = NumQst % 2; Gbl.RowEvenOdd = NumQst % 2;
/***** Create test question *****/
Tst_QstConstructor (&Question);
/***** Get question data *****/
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/* /*
row[0] QstInd row[0] QstInd
row[1] QstCod row[1] QstCod
*/ */
/***** Create test question *****/
Tst_QstConstructor (&Question);
/* Get question index (row[0]) */ /* Get question index (row[0]) */
QstInd = Str_ConvertStrToUnsigned (row[0]); QstInd = Str_ConvertStrToUnsigned (row[0]);
@ -1917,7 +1919,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
QstInd); QstInd);
/* Get question code (row[1]) */ /* Get question code (row[1]) */
QstCod = Str_ConvertStrCodToLongCod (row[1]); Question.QstCod = Str_ConvertStrCodToLongCod (row[1]);
/***** Icons *****/ /***** Icons *****/
Gam_SetCurrentGamCod (GamCod); // Used to pass parameter Gam_SetCurrentGamCod (GamCod); // Used to pass parameter
@ -1965,14 +1967,14 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
/* Put icon to edit the question */ /* Put icon to edit the question */
if (ICanEditQuestions) if (ICanEditQuestions)
{ {
Tst_SetParamGblQstCod (QstCod); Tst_SetParamGblQstCod (Question.QstCod);
Ico_PutContextualIconToEdit (ActEdiOneTstQst,NULL,Tst_PutParamGblQstCod); Ico_PutContextualIconToEdit (ActEdiOneTstQst,NULL,Tst_PutParamGblQstCod);
} }
HTM_TD_End (); HTM_TD_End ();
/***** Question *****/ /***** Question *****/
Gam_ListQuestionForEdition (QstCod,QstInd); Gam_ListQuestionForEdition (&Question,QstInd);
HTM_TR_End (); HTM_TR_End ();
@ -1988,7 +1990,8 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
/********************** List game question for edition ***********************/ /********************** List game question for edition ***********************/
/*****************************************************************************/ /*****************************************************************************/
static void Gam_ListQuestionForEdition (long QstCod,unsigned QstInd) static void Gam_ListQuestionForEdition (struct Tst_Question *Question,
unsigned QstInd)
{ {
extern const char *Txt_Question_removed; extern const char *Txt_Question_removed;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
@ -1998,7 +2001,7 @@ static void Gam_ListQuestionForEdition (long QstCod,unsigned QstInd)
struct Media Media; struct Media Media;
/***** Get question from database *****/ /***** Get question from database *****/
QstExists = Tst_GetOneQuestionByCod (QstCod,&mysql_res); // Question exists? QstExists = Tst_GetOneQuestionByCod (Question->QstCod,&mysql_res); // Question exists?
if (QstExists) if (QstExists)
{ {
@ -2029,13 +2032,13 @@ static void Gam_ListQuestionForEdition (long QstCod,unsigned QstInd)
/***** Write question code *****/ /***** Write question code *****/
HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd);
HTM_TxtF ("%ld ",QstCod); HTM_TxtF ("%ld ",Question->QstCod);
HTM_TD_End (); HTM_TD_End ();
/***** Write the question tags *****/ /***** Write the question tags *****/
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
if (QstExists) if (QstExists)
Tst_GetAndWriteTagsQst (QstCod); Tst_GetAndWriteTagsQst (Question->QstCod);
HTM_TD_End (); HTM_TD_End ();
/***** Write stem (row[3]) and media *****/ /***** Write stem (row[3]) and media *****/
@ -2059,7 +2062,7 @@ static void Gam_ListQuestionForEdition (long QstCod,unsigned QstInd)
Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT"); Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT");
/* Show answers */ /* Show answers */
Tst_WriteAnswersEdit (QstCod,AnswerType); Tst_WriteAnswersEdit (Question);
} }
else else
{ {

View File

@ -140,7 +140,7 @@ static void Mch_ShowLstGrpsToCreateMatch (void);
static long Mch_CreateMatch (long GamCod,char Title[Gam_MAX_BYTES_TITLE + 1]); static long Mch_CreateMatch (long GamCod,char Title[Gam_MAX_BYTES_TITLE + 1]);
static void Mch_CreateIndexes (long GamCod,long MchCod); static void Mch_CreateIndexes (long GamCod,long MchCod);
static void Mch_ReorderAnswer (long MchCod,unsigned QstInd, static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
long QstCod,bool Shuffle); const struct Tst_Question *Question);
static void Mch_CreateGrps (long MchCod); static void Mch_CreateGrps (long MchCod);
static void Mch_UpdateMatchStatusInDB (const struct Match *Match); static void Mch_UpdateMatchStatusInDB (const struct Match *Match);
@ -1448,11 +1448,9 @@ static void Mch_CreateIndexes (long GamCod,long MchCod)
MYSQL_ROW row; MYSQL_ROW row;
unsigned NumQsts; unsigned NumQsts;
unsigned NumQst; unsigned NumQst;
long QstCod; struct Tst_Question Question;
long LongNum; long LongNum;
unsigned QstInd; unsigned QstInd;
Tst_AnswerType_t AnswerType;
bool Shuffle;
/***** Get questions of the game *****/ /***** Get questions of the game *****/
NumQsts = (unsigned) NumQsts = (unsigned)
@ -1472,11 +1470,20 @@ static void Mch_CreateIndexes (long GamCod,long MchCod)
NumQst < NumQsts; NumQst < NumQsts;
NumQst++) NumQst++)
{ {
/***** Create test question *****/
Tst_QstConstructor (&Question);
/***** Get question data *****/ /***** Get question data *****/
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/*
gam_questions.QstCod row[0]
gam_questions.QstInd row[1]
tst_questions.AnsType row[2]
tst_questions.Shuffle row[3]
*/
/* Get question code (row[0]) */ /* Get question code (row[0]) */
if ((QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) if ((Question.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]) */
@ -1485,15 +1492,18 @@ static void Mch_CreateIndexes (long GamCod,long MchCod)
QstInd = (unsigned) LongNum; QstInd = (unsigned) LongNum;
/* Get answer type (row[2]) */ /* Get answer type (row[2]) */
AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[2]); Question.Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[2]);
if (AnswerType != Tst_ANS_UNIQUE_CHOICE) if (Question.Answer.Type != Tst_ANS_UNIQUE_CHOICE)
Lay_ShowErrorAndExit ("Wrong answer type."); Lay_ShowErrorAndExit ("Wrong answer type.");
/* Get shuffle (row[3]) */ /* Get shuffle (row[3]) */
Shuffle = (row[3][0] == 'Y'); Question.Shuffle = (row[3][0] == 'Y');
/***** Reorder answer *****/ /***** Reorder answer *****/
Mch_ReorderAnswer (MchCod,QstInd,QstCod,Shuffle); Mch_ReorderAnswer (MchCod,QstInd,&Question);
/***** Destroy test question *****/
Tst_QstDestructor (&Question);
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
@ -1505,7 +1515,7 @@ static void Mch_CreateIndexes (long GamCod,long MchCod)
/*****************************************************************************/ /*****************************************************************************/
static void Mch_ReorderAnswer (long MchCod,unsigned QstInd, static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
long QstCod,bool Shuffle) const struct Tst_Question *Question)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
@ -1526,9 +1536,9 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
" FROM tst_answers" " FROM tst_answers"
" WHERE QstCod=%ld" " WHERE QstCod=%ld"
" ORDER BY %s", " ORDER BY %s",
QstCod, Question->QstCod,
Shuffle ? "RAND()" : // Use RAND() because is really random; RAND(NOW()) repeats order Question->Shuffle ? "RAND()" : // Use RAND() because is really random; RAND(NOW()) repeats order
"AnsInd"); "AnsInd");
/***** For each answer in question... *****/ /***** For each answer in question... *****/
for (NumAns = 0; for (NumAns = 0;
@ -3799,34 +3809,30 @@ static void Mch_ComputeScore (struct TsR_Result *Result)
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question
bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION]; bool AnswersUsr[Tst_MAX_OPTIONS_PER_QUESTION];
/***** Create test question *****/ for (NumQst = 0, Result->Score = 0.0;
Tst_QstConstructor (&Question);
Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE;
Result->Score = 0.0;
for (NumQst = 0;
NumQst < Result->NumQsts; NumQst < Result->NumQsts;
NumQst++) NumQst++)
{ {
/***** Get indexes for this question from string *****/ /***** Create test question *****/
Tst_GetIndexesFromStr (Result->StrIndexes[NumQst],Indexes); Tst_QstConstructor (&Question);
Question.QstCod = Result->QstCodes[NumQst];
/***** Get the user's answers for this question from string *****/ Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE;
Tst_GetAnswersFromStr (Result->StrAnswers[NumQst],AnswersUsr);
/***** Get correct answers of test question from database *****/ /***** Get correct answers of test question from database *****/
Tst_GetCorrectAnswersFromDB (Result->QstCodes[NumQst],&Question); Tst_GetCorrectAnswersFromDB (&Question);
/***** Compute the total score of this question *****/ /***** Compute the score of this question *****/
Tst_GetIndexesFromStr (Result->StrIndexes[NumQst],Indexes);
Tst_GetAnswersFromStr (Result->StrAnswers[NumQst],AnswersUsr);
Tst_ComputeScoreQst (&Question, Tst_ComputeScoreQst (&Question,
Indexes,AnswersUsr,&ScoreThisQst,&AnswerIsNotBlank); Indexes,AnswersUsr,&ScoreThisQst,&AnswerIsNotBlank);
/***** Update total score *****/ /***** Update total score *****/
Result->Score += ScoreThisQst; Result->Score += ScoreThisQst;
}
/***** Destroy test question *****/ /***** Destroy test question *****/
Tst_QstDestructor (&Question); Tst_QstDestructor (&Question);
}
} }
/*****************************************************************************/ /*****************************************************************************/

File diff suppressed because it is too large Load Diff

View File

@ -98,6 +98,8 @@ struct Tst_Test
struct Tst_Question struct Tst_Question
{ {
long QstCod;
struct Tst_Tags Tags;
struct struct
{ {
char *Text; char *Text;
@ -176,15 +178,14 @@ void Tst_ListQuestionsToSelect (void);
bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res); bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res);
void Tst_WriteParamEditQst (void); void Tst_WriteParamEditQst (void);
void Tst_SetParamGblTags (const struct Tst_Tags *TagsSrc); void Tst_SetParamGblTest (const struct Tst_Test *TestSrc);
void Tst_SetParamGblAnswerTypes (const struct Tst_AnswerTypes *AnswerTypesSrc); void Tst_GetParamGblTest (struct Tst_Test *TestDst);
void Tst_SetParamGblSelectedOrder (Tst_QuestionsOrder_t SelectedOrder);
Tst_QuestionsOrder_t Tst_GetParamGblSelectedOrder (void);
unsigned Tst_GetNumAnswersQst (long QstCod); unsigned Tst_GetNumAnswersQst (long QstCod);
unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle); void Tst_GetAnswersQst (struct Tst_Question *Question,MYSQL_RES **mysql_res,
void Tst_GetCorrectAnswersFromDB (long QstCod,struct Tst_Question *Question); bool Shuffle);
void Tst_WriteAnswersEdit (long QstCod,Tst_AnswerType_t AnswerType); void Tst_GetCorrectAnswersFromDB (struct Tst_Question *Question);
void Tst_WriteAnswersEdit (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. void Tst_GetIndexesFromStr (const char StrIndexesOneQst[Tst_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc.
@ -214,14 +215,13 @@ void Tst_ShowFormEditOneQst (void);
void Tst_QstConstructor (struct Tst_Question *Question); void Tst_QstConstructor (struct Tst_Question *Question);
void Tst_QstDestructor (struct Tst_Question *Question); void Tst_QstDestructor (struct Tst_Question *Question);
int Tst_AllocateTextChoiceAnswer (struct Tst_Question *Question,unsigned NumOpt); bool Tst_AllocateTextChoiceAnswer (struct Tst_Question *Question,unsigned NumOpt);
Tst_AnswerType_t Tst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD); Tst_AnswerType_t Tst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD);
void Tst_ReceiveQst (void); void Tst_ReceiveQst (void);
bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Question, bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Question);
const struct Tst_Tags *Tags);
bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question); bool Tst_CheckIfQuestionExistsInDB (struct Tst_Question *Question);
long Tst_GetIntAnsFromStr (char *Str); long Tst_GetIntAnsFromStr (char *Str);
@ -237,9 +237,7 @@ long Tst_GetParamGblQstCod (void);
void Tst_PutParamGblQstCod (void); void Tst_PutParamGblQstCod (void);
void Tst_PutParamQstCod (long QstCod); void Tst_PutParamQstCod (long QstCod);
long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod, void Tst_InsertOrUpdateQstTagsAnsIntoDB (struct Tst_Question *Question);
struct Tst_Question *Question,
const struct Tst_Tags *Tags);
void Tst_RemoveCrsTests (long CrsCod); void Tst_RemoveCrsTests (long CrsCod);

View File

@ -71,7 +71,7 @@ static void TsI_PutCreateXMLParam (void);
static void TsI_ExportQuestion (long QstCod,FILE *FileXML); static void TsI_ExportQuestion (long QstCod,FILE *FileXML);
static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML); static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML);
static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType, static void TsI_WriteAnswersOfAQstXML (struct Tst_Question *Question,
FILE *FileXML); FILE *FileXML);
static void TsI_ReadQuestionsFromXMLFileAndStoreInDB (const char *FileNameXML); static void TsI_ReadQuestionsFromXMLFileAndStoreInDB (const char *FileNameXML);
static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer); static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer);
@ -81,7 +81,6 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem,
static void TsI_WriteHeadingListImportedQst (void); static void TsI_WriteHeadingListImportedQst (void);
static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
struct XMLElement *FeedbackElem, struct XMLElement *FeedbackElem,
const struct Tst_Tags *Tags,
const struct Tst_Question *Question, const struct Tst_Question *Question,
bool QuestionExists); bool QuestionExists);
@ -94,9 +93,7 @@ void TsI_PutFormToExportQuestions (const struct Tst_Test *Test)
extern const char *Txt_Export_questions; extern const char *Txt_Export_questions;
/***** Put a link to create a file with questions *****/ /***** Put a link to create a file with questions *****/
Tst_SetParamGblTags (&Test->Tags); Tst_SetParamGblTest (Test);
Tst_SetParamGblAnswerTypes (&Test->AnswerTypes);
Tst_SetParamGblSelectedOrder (Test->SelectedOrder);
Lay_PutContextualLinkIconText (ActLstTstQst,NULL,TsI_PutParamsExportQsts, Lay_PutContextualLinkIconText (ActLstTstQst,NULL,TsI_PutParamsExportQsts,
"file-import.svg", "file-import.svg",
Txt_Export_questions); Txt_Export_questions);
@ -108,11 +105,13 @@ void TsI_PutFormToExportQuestions (const struct Tst_Test *Test)
static void TsI_PutParamsExportQsts (void) static void TsI_PutParamsExportQsts (void)
{ {
struct Tst_Test Test;
Tst_GetParamGblTest (&Test);
Dat_WriteParamsIniEndDates (); Dat_WriteParamsIniEndDates ();
Tst_WriteParamEditQst (); Tst_WriteParamEditQst ();
Par_PutHiddenParamChar ("OnlyThisQst",'N'); Par_PutHiddenParamChar ("OnlyThisQst",'N');
Par_PutHiddenParamUnsigned (NULL,"Order", Par_PutHiddenParamUnsigned (NULL,"Order",(unsigned) Test.SelectedOrder);
(unsigned) Tst_GetParamGblSelectedOrder ());
TsI_PutCreateXMLParam (); TsI_PutCreateXMLParam ();
} }
@ -250,7 +249,10 @@ static void TsI_ExportQuestion (long QstCod,FILE *FileXML)
extern const char *Txt_NEW_LINE; extern const char *Txt_NEW_LINE;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
Tst_AnswerType_t AnswerType; struct Tst_Question Question;
/***** Create test question *****/
Tst_QstConstructor (&Question);
if (Tst_GetOneQuestionByCod (QstCod,&mysql_res)) if (Tst_GetOneQuestionByCod (QstCod,&mysql_res))
{ {
@ -269,9 +271,9 @@ static void TsI_ExportQuestion (long QstCod,FILE *FileXML)
*/ */
/***** Write the answer type (row[1]) *****/ /***** Write the answer type (row[1]) *****/
AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); Question.Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
fprintf (FileXML,"<question type=\"%s\">%s", fprintf (FileXML,"<question type=\"%s\">%s",
Tst_StrAnswerTypesXML[AnswerType],Txt_NEW_LINE); Tst_StrAnswerTypesXML[Question.Answer.Type],Txt_NEW_LINE);
/***** Write the question tags *****/ /***** Write the question tags *****/
fprintf (FileXML,"<tags>%s",Txt_NEW_LINE); fprintf (FileXML,"<tags>%s",Txt_NEW_LINE);
@ -291,19 +293,22 @@ static void TsI_ExportQuestion (long QstCod,FILE *FileXML)
/***** Write the answers of this question. /***** Write the answers of this question.
Shuffle can be enabled or disabled (row[2]) *****/ Shuffle can be enabled or disabled (row[2]) *****/
fprintf (FileXML,"<answer"); fprintf (FileXML,"<answer");
if (AnswerType == Tst_ANS_UNIQUE_CHOICE || if (Question.Answer.Type == Tst_ANS_UNIQUE_CHOICE ||
AnswerType == Tst_ANS_MULTIPLE_CHOICE) Question.Answer.Type == Tst_ANS_MULTIPLE_CHOICE)
fprintf (FileXML," shuffle=\"%s\"", fprintf (FileXML," shuffle=\"%s\"",
(row[2][0] == 'Y') ? "yes" : (row[2][0] == 'Y') ? "yes" :
"no"); "no");
fprintf (FileXML,">"); fprintf (FileXML,">");
TsI_WriteAnswersOfAQstXML (QstCod,AnswerType,FileXML); TsI_WriteAnswersOfAQstXML (&Question,FileXML);
fprintf (FileXML,"</answer>%s",Txt_NEW_LINE); fprintf (FileXML,"</answer>%s",Txt_NEW_LINE);
/***** End question *****/ /***** End question *****/
fprintf (FileXML,"</question>%s%s", fprintf (FileXML,"</question>%s%s",
Txt_NEW_LINE,Txt_NEW_LINE); Txt_NEW_LINE,Txt_NEW_LINE);
} }
/***** Destroy test question *****/
Tst_QstDestructor (&Question);
} }
/*****************************************************************************/ /*****************************************************************************/
@ -337,21 +342,19 @@ static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML)
/**************** Get and write the answers of a test question ***************/ /**************** Get and write the answers of a test question ***************/
/*****************************************************************************/ /*****************************************************************************/
static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType, static void TsI_WriteAnswersOfAQstXML (struct Tst_Question *Question,
FILE *FileXML) FILE *FileXML)
{ {
extern const char *Txt_NEW_LINE; extern const char *Txt_NEW_LINE;
struct Tst_Question Question;
unsigned NumOpt; unsigned NumOpt;
unsigned i; unsigned i;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
double FloatNum[2]; double FloatNum[2];
Question.Answer.Type = AnswerType;
/***** Get answers *****/ /***** Get answers *****/
Question.Answer.NumOptions = Tst_GetAnswersQst (QstCod,&mysql_res,false); // Result: AnsInd,Answer,Correct Tst_GetAnswersQst (Question,&mysql_res,
false); // Don't shuffle
/* /*
row[0] AnsInd row[0] AnsInd
row[1] Answer row[1] Answer
@ -361,16 +364,16 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType,
*/ */
/***** Write answers *****/ /***** Write answers *****/
switch (Question.Answer.Type) switch (Question->Answer.Type)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
Tst_CheckIfNumberOfAnswersIsOne (&Question); Tst_CheckIfNumberOfAnswersIsOne (Question);
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
fprintf (FileXML,"%ld", fprintf (FileXML,"%ld",
Tst_GetIntAnsFromStr (row[1])); Tst_GetIntAnsFromStr (row[1]));
break; break;
case Tst_ANS_FLOAT: case Tst_ANS_FLOAT:
if (Question.Answer.NumOptions != 2) if (Question->Answer.NumOptions != 2)
Lay_ShowErrorAndExit ("Wrong float range."); Lay_ShowErrorAndExit ("Wrong float range.");
for (i = 0; for (i = 0;
@ -388,7 +391,7 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType,
FloatNum[1],Txt_NEW_LINE); FloatNum[1],Txt_NEW_LINE);
break; break;
case Tst_ANS_TRUE_FALSE: case Tst_ANS_TRUE_FALSE:
Tst_CheckIfNumberOfAnswersIsOne (&Question); Tst_CheckIfNumberOfAnswersIsOne (Question);
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
fprintf (FileXML,"%s", fprintf (FileXML,"%s",
row[1][0] == 'T' ? "true" : row[1][0] == 'T' ? "true" :
@ -399,7 +402,7 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType,
case Tst_ANS_TEXT: case Tst_ANS_TEXT:
fprintf (FileXML,"%s",Txt_NEW_LINE); fprintf (FileXML,"%s",Txt_NEW_LINE);
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Question.Answer.NumOptions; NumOpt < Question->Answer.NumOptions;
NumOpt++) NumOpt++)
{ {
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
@ -408,7 +411,7 @@ static void TsI_WriteAnswersOfAQstXML (long QstCod,Tst_AnswerType_t AnswerType,
fprintf (FileXML,"<option"); fprintf (FileXML,"<option");
/* Write whether the answer is correct or not (row[4]) */ /* Write whether the answer is correct or not (row[4]) */
if (Question.Answer.Type != Tst_ANS_TEXT) if (Question->Answer.Type != Tst_ANS_TEXT)
fprintf (FileXML," correct=\"%s\"", fprintf (FileXML," correct=\"%s\"",
(row[4][0] == 'Y') ? "yes" : (row[4][0] == 'Y') ? "yes" :
"no"); "no");
@ -541,10 +544,9 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
struct XMLElement *FeedbackElem; struct XMLElement *FeedbackElem;
struct XMLElement *AnswerElem; struct XMLElement *AnswerElem;
struct XMLAttribute *Attribute; struct XMLAttribute *Attribute;
struct Tst_Tags Tags;
bool AnswerTypeFound;
bool QuestionExists;
struct Tst_Question Question; struct Tst_Question Question;
bool QuestionExists;
bool AnswerTypeFound;
char Stem[Cns_MAX_BYTES_TEXT + 1]; char Stem[Cns_MAX_BYTES_TEXT + 1];
char Feedback[Cns_MAX_BYTES_TEXT + 1]; char Feedback[Cns_MAX_BYTES_TEXT + 1];
@ -605,22 +607,22 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
if (AnswerTypeFound) if (AnswerTypeFound)
{ {
/* Get tags */ /* Get tags */
for (TagsElem = QuestionElem->FirstChild, Tags.Num = 0; for (TagsElem = QuestionElem->FirstChild, Question.Tags.Num = 0;
TagsElem != NULL; TagsElem != NULL;
TagsElem = TagsElem->NextBrother) TagsElem = TagsElem->NextBrother)
if (!strcmp (TagsElem->TagName,"tags")) if (!strcmp (TagsElem->TagName,"tags"))
{ {
for (TagElem = TagsElem->FirstChild; for (TagElem = TagsElem->FirstChild;
TagElem != NULL && Tags.Num < Tst_MAX_TAGS_PER_QUESTION; TagElem != NULL && Question.Tags.Num < Tst_MAX_TAGS_PER_QUESTION;
TagElem = TagElem->NextBrother) TagElem = TagElem->NextBrother)
if (!strcmp (TagElem->TagName,"tag")) if (!strcmp (TagElem->TagName,"tag"))
{ {
if (TagElem->Content) if (TagElem->Content)
{ {
Str_Copy (Tags.Txt[Tags.Num], Str_Copy (Question.Tags.Txt[Question.Tags.Num],
TagElem->Content, TagElem->Content,
Tst_MAX_BYTES_TAG); Tst_MAX_BYTES_TAG);
Tags.Num++; Question.Tags.Num++;
} }
} }
break; // Only first element "tags" break; // Only first element "tags"
@ -691,19 +693,23 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
TsI_GetAnswerFromXML (AnswerElem,&Question); TsI_GetAnswerFromXML (AnswerElem,&Question);
/* Make sure that tags, text and answer are not empty */ /* Make sure that tags, text and answer are not empty */
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question,&Tags)) if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question))
{ {
/* Check if question already exists in database */ /* Check if question already exists in database */
QuestionExists = Tst_CheckIfQuestionExistsInDB (&Question); QuestionExists = Tst_CheckIfQuestionExistsInDB (&Question);
/* Write row with this imported question */ /* Write row with this imported question */
TsI_WriteRowImportedQst (StemElem,FeedbackElem, TsI_WriteRowImportedQst (StemElem,FeedbackElem,
&Tags,&Question,QuestionExists); &Question,QuestionExists);
/***** If a new question ==> insert question, tags and answer in the database *****/ /***** If a new question ==> insert question, tags and answer in the database *****/
if (!QuestionExists) if (!QuestionExists)
if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L,&Question,&Tags) <= 0) {
Question.QstCod = -1L;
Tst_InsertOrUpdateQstTagsAnsIntoDB (&Question);
if (Question.QstCod <= 0)
Lay_ShowErrorAndExit ("Can not create question."); Lay_ShowErrorAndExit ("Can not create question.");
}
} }
} }
else // Answer type not found else // Answer type not found
@ -923,7 +929,6 @@ static void TsI_WriteHeadingListImportedQst (void)
static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
struct XMLElement *FeedbackElem, struct XMLElement *FeedbackElem,
const struct Tst_Tags *Tags,
const struct Tst_Question *Question, const struct Tst_Question *Question,
bool QuestionExists) bool QuestionExists)
{ {
@ -971,12 +976,12 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
/***** Write the question tags *****/ /***** Write the question tags *****/
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
if (Tags->Num) if (Question->Tags.Num)
{ {
/***** Write the tags *****/ /***** Write the tags *****/
HTM_TABLE_Begin (NULL); HTM_TABLE_Begin (NULL);
for (NumTag = 0; for (NumTag = 0;
NumTag < Tags->Num; NumTag < Question->Tags.Num;
NumTag++) NumTag++)
{ {
HTM_TR_Begin (NULL); HTM_TR_Begin (NULL);
@ -986,7 +991,7 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
HTM_TD_End (); HTM_TD_End ();
HTM_TD_Begin ("class=\"%s LT\"",ClassData); HTM_TD_Begin ("class=\"%s LT\"",ClassData);
HTM_Txt (Tags->Txt[NumTag]); HTM_Txt (Question->Tags.Txt[NumTag]);
HTM_TD_End (); HTM_TD_End ();
HTM_TR_End (); HTM_TR_End ();