diff --git a/swad_changelog.h b/swad_changelog.h index 10285095..4eed5d2d 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -497,7 +497,7 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - * En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 19.160.1 (2020-04-03)" +#define Log_PLATFORM_VERSION "SWAD 19.161 (2020-04-04)" #define CSS_FILE "swad19.146.css" #define JS_FILE "swad19.153.js" /* @@ -516,6 +516,10 @@ Si es as Función API newLocation... Paramétros: MAC, string con ubicación (ej. "Aula 0.1") +// TODO: Laura García: "Ahora estoy utilizando la plataforma SWAD más que nunca, evidentemente, debido a las circunstancias, e incluso les he hecho un examencillo a los alumnos utilizando los test de autoevaluación. + Pero quería preguntarte un par de cosas: + - lo primero es si se pueden borrar los test realizados por cualquier usuario, incluido profesores. Yo misma he hecho un montón para simular el examen, y ya me están sobrando. + - por otra parte, he buscado pero no he encontrado, la posibilidad de cambiar la manera de corregir los tes, quitar la penalización por respuesta negativa,, o cambiarla, etc.. La verdad es que si se puede hacer me facilitaría un montón el trabajo próximo que nos espera con los alumnos." // TODO: Hacer un nuevo rol en los TFG: tutor externo (profesor de áreas no vinculadas con el centro, profesionales de empresas, etc.) // TODO: Impedir la creación y edición de proyectos si no son editables. // TODO: No se puede entrar con DNI '1' suponiendo que no tenga password ¿por qué? @@ -524,9 +528,8 @@ Param // TODO: Oresti Baños: cambiar ojos por candados en descriptores para prohibir/permitir y dejar los ojos para poder elegir descriptores // TODO: Integrar pull requests con traducciones del alemán del usuario eruedin en GitHub // TODO: Integrar Stem y Feedback en question, creando espacio con malloc como en las respuestas -// TODO: Intentar cambiar Tst_WriteChoiceAnsSeeing usando Tst_GetQstDataFromDB y quitar Tst_GetChoiceAns -// TODO: Intentar quitar Tst_GetOneQuestionByCod usando Tst_GetQstDataFromDB + Version 19.161: Apr 04, 2020 Code refactoring in tests. (284529 lines) Version 19.160.1: Apr 03, 2020 Score calculated is removed from each test question. (284817 lines) Version 19.160: Apr 03, 2020 The score for each test question displayed in an exam is the one stored in the database instead of being calculated. New file extension, suggested by Rosa Medina Doménech. (284933 lines) diff --git a/swad_game.c b/swad_game.c index c536b10d..937e3561 100644 --- a/swad_game.c +++ b/swad_game.c @@ -156,8 +156,9 @@ static void Gam_ListGameQuestions (struct Game *Game); static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, MYSQL_RES *mysql_res, bool ICanEditQuestions); -static void Gam_ListQuestionForEdition (struct Tst_Question *Question, - unsigned QstInd); +static void Gam_ListQuestionForEdition (const struct Tst_Question *Question, + const char *Stem,const char *Feedback, + unsigned QstInd,bool QuestionExists); static void Gam_PutIconToAddNewQuestions (void *Args); static void Gam_PutButtonToAddNewQuestions (void); @@ -1911,9 +1912,12 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, unsigned NumQst; MYSQL_ROW row; struct Tst_Question Question; + char Stem[Cns_MAX_BYTES_TEXT + 1]; + char Feedback[Cns_MAX_BYTES_TEXT + 1]; unsigned QstInd; unsigned MaxQstInd; char StrQstInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; + bool QuestionExists; /***** Get maximum question index *****/ MaxQstInd = Gam_GetMaxQuestionIndexInGame (GamCod); @@ -2010,7 +2014,8 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, HTM_TD_End (); /***** Question *****/ - Gam_ListQuestionForEdition (&Question,QstInd); + QuestionExists = Tst_GetQstDataFromDB (&Question,Stem,Feedback); + Gam_ListQuestionForEdition (&Question,Stem,Feedback,QstInd,QuestionExists); HTM_TR_End (); @@ -2026,44 +2031,17 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, /********************** List game question for edition ***********************/ /*****************************************************************************/ -static void Gam_ListQuestionForEdition (struct Tst_Question *Question, - unsigned QstInd) +static void Gam_ListQuestionForEdition (const struct Tst_Question *Question, + const char *Stem,const char *Feedback, + unsigned QstInd,bool QuestionExists) { extern const char *Txt_Question_removed; - MYSQL_RES *mysql_res; - MYSQL_ROW row; - bool QstExists; - Tst_AnswerType_t AnswerType; - struct Media Media; - - /***** Get question from database *****/ - QstExists = Tst_GetOneQuestionByCod (Question->QstCod,&mysql_res); // Question exists? - - if (QstExists) - { - /***** Get row of the result of the query *****/ - row = mysql_fetch_row (mysql_res); - /* - row[0] UNIX_TIMESTAMP(EditTime) - row[1] AnsType - row[2] Shuffle - row[3] Stem - row[4] Feedback - row[5] MedCod - row[6] NumHits - row[7] NumHitsNotBlank - row[8] Score - */ - } /***** Number of question and answer type (row[1]) *****/ HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); Tst_WriteNumQst (QstInd); - if (QstExists) - { - AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); - Tst_WriteAnswerType (AnswerType); - } + if (QuestionExists) + Tst_WriteAnswerType (Question->Answer.Type); HTM_TD_End (); /***** Write question code *****/ @@ -2073,29 +2051,25 @@ static void Gam_ListQuestionForEdition (struct Tst_Question *Question, /***** Write the question tags *****/ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); - if (QstExists) + if (QuestionExists) Tst_GetAndWriteTagsQst (Question->QstCod); HTM_TD_End (); /***** Write stem (row[3]) and media *****/ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); - if (QstExists) + if (QuestionExists) { /* Write stem */ - Tst_WriteQstStem (row[3],"TEST_EDI", + Tst_WriteQstStem (Stem,"TEST_EDI", true); // Visible - /* Get media (row[5]) */ - Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); - Med_GetMediaDataByCod (&Media); - /* Show media */ - Med_ShowMedia (&Media, + Med_ShowMedia (&Question->Media, "TEST_MED_EDIT_LIST_STEM_CONTAINER", "TEST_MED_EDIT_LIST_STEM"); - /* Show feedback (row[4]) */ - Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT"); + /* Show feedback */ + Tst_WriteQstFeedback (Feedback,"TEST_EDI_LIGHT"); /* Show answers */ Tst_WriteAnswersListing (Question); @@ -2107,9 +2081,6 @@ static void Gam_ListQuestionForEdition (struct Tst_Question *Question, HTM_SPAN_End (); } HTM_TD_End (); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ diff --git a/swad_match.c b/swad_match.c index b231a3b6..0342163e 100644 --- a/swad_match.c +++ b/swad_match.c @@ -192,7 +192,7 @@ static void Mch_PutIfAnswered (const struct Match *Match,bool Answered); static void Mch_PutIconToRemoveMyAnswer (const struct Match *Match); static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match); static void Mch_WriteAnswersMatchResult (const struct Match *Match, - struct Tst_Question *Question, + const struct Tst_Question *Question, const char *Class,bool ShowResult); static bool Mch_ShowQuestionAndAnswersStd (const struct Match *Match, const struct Mch_UsrAnswer *UsrAnswer, @@ -2889,9 +2889,9 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match) { extern const char *Txt_MATCH_Paused; extern const char *Txt_Question_removed; - MYSQL_RES *mysql_res; - MYSQL_ROW row; struct Tst_Question Question; + char Stem[Cns_MAX_BYTES_TEXT + 1]; + char Feedback[Cns_MAX_BYTES_TEXT + 1]; /***** Create test question *****/ Tst_QstConstructor (&Question); @@ -2908,41 +2908,25 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match) } /***** Get data of question from database *****/ - if (DB_QuerySELECT (&mysql_res,"can not get data of a question", - "SELECT AnsType," // row[0] - "Stem," // row[1] - "MedCod" // row[2] - " FROM tst_questions" - " WHERE QstCod=%ld", - Question.QstCod)) + if (Tst_GetQstDataFromDB (&Question,Stem,Feedback)) { - row = mysql_fetch_row (mysql_res); - /***** Show question *****/ - /* Get answer type (row[0]) */ - Question.Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]); + /* Check answer type */ if (Question.Answer.Type != Tst_ANS_UNIQUE_CHOICE) Lay_ShowErrorAndExit ("Wrong answer type."); /* Begin container */ HTM_DIV_Begin ("class=\"MCH_BOTTOM\""); // Bottom - /* Write stem (row[1]) */ - Tst_WriteQstStem (row[1],"MCH_TCH_STEM", + /* Write stem */ + Tst_WriteQstStem (Stem,"MCH_TCH_STEM", true); // Visible - /* Get media (row[2]) */ - Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[2]); - Med_GetMediaDataByCod (&Question.Media); - /* Show media */ Med_ShowMedia (&Question.Media, "TEST_MED_EDIT_LIST_STEM_CONTAINER", "TEST_MED_EDIT_LIST_STEM"); - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - /***** Write answers? *****/ switch (Match->Status.Showing) { @@ -2983,7 +2967,7 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match) /*****************************************************************************/ static void Mch_WriteAnswersMatchResult (const struct Match *Match, - struct Tst_Question *Question, + const struct Tst_Question *Question, const char *Class,bool ShowResult) { /***** Write answer depending on type *****/ @@ -3000,13 +2984,11 @@ static void Mch_WriteAnswersMatchResult (const struct Match *Match, /*****************************************************************************/ void Mch_WriteChoiceAnsViewMatch (const struct Match *Match, - struct Tst_Question *Question, + const struct Tst_Question *Question, const char *Class,bool ShowResult) { unsigned NumOpt; bool RowIsOpen = false; - MYSQL_RES *mysql_res; - MYSQL_ROW row; unsigned NumRespondersQst; unsigned NumRespondersAns; unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question @@ -3014,47 +2996,6 @@ void Mch_WriteChoiceAnsViewMatch (const struct Match *Match, /***** Get number of users who have answered this question from database *****/ NumRespondersQst = Mch_GetNumUsrsWhoAnsweredQst (Match->MchCod,Match->Status.QstInd); - /***** Get answers of a question from database *****/ - Tst_GetAnswersQst (Question,&mysql_res, - false); // Don't shuffle - /* - row[0] AnsInd - row[1] Answer - row[2] Feedback - row[3] MedCod - row[4] Correct - */ - - for (NumOpt = 0; - NumOpt < Question->Answer.NumOptions; - NumOpt++) - { - /* Get next answer */ - row = mysql_fetch_row (mysql_res); - - /* Allocate memory for text in this choice answer */ - if (!Tst_AllocateTextChoiceAnswer (Question,NumOpt)) - /* Abort on error */ - Ale_ShowAlertsAndExit (); - - /* Copy text (row[1]) and convert it, that is in HTML, to rigorous HTML */ - Str_Copy (Question->Answer.Options[NumOpt].Text,row[1], - Tst_MAX_BYTES_ANSWER_OR_FEEDBACK); - Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, - Question->Answer.Options[NumOpt].Text, - Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); - - /* Get media (row[3]) */ - Question->Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); - Med_GetMediaDataByCod (&Question->Answer.Options[NumOpt].Media); - - /* Get if correct (row[4]) */ - Question->Answer.Options[NumOpt].Correct = (row[4][0] == 'Y'); - } - - /* Free structure that stores the query result */ - DB_FreeMySQLResult (&mysql_res); - /***** Get indexes for this question in match *****/ Mch_GetIndexes (Match->MchCod,Match->Status.QstInd,Indexes); @@ -3083,7 +3024,13 @@ void Mch_WriteChoiceAnsViewMatch (const struct Match *Match, /***** Write the option text and the result *****/ HTM_TD_Begin ("class=\"LT\""); HTM_LABEL_Begin ("for=\"Ans%06u_%u\" class=\"%s\"",Match->Status.QstInd,NumOpt,Class); + + /* Convert text, that is in HTML, to rigorous HTML */ + Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, + Question->Answer.Options[NumOpt].Text, + Tst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); HTM_Txt (Question->Answer.Options[Indexes[NumOpt]].Text); + HTM_LABEL_End (); Med_ShowMedia (&Question->Answer.Options[Indexes[NumOpt]].Media, "TEST_MED_SHOW_CONT", diff --git a/swad_match.h b/swad_match.h index e4e603fb..58d91c6a 100644 --- a/swad_match.h +++ b/swad_match.h @@ -118,7 +118,7 @@ unsigned Mch_GetNumUnfinishedMchsInGame (long GamCod); bool Mch_CheckIfICanPlayThisMatchBasedOnGrps (const struct Match *Match); void Mch_WriteChoiceAnsViewMatch (const struct Match *Match, - struct Tst_Question *Question, + const struct Tst_Question *Question, const char *Class,bool ShowResult); bool Mch_RegisterMeAsPlayerInMatch (struct Match *Match); diff --git a/swad_test.c b/swad_test.c index a5309eb3..1c4149d7 100644 --- a/swad_test.c +++ b/swad_test.c @@ -149,10 +149,10 @@ static void Tst_ShowTestExamToFillIt (struct TstExa_Exam *Exam, unsigned NumExamsGeneratedByMe, Tst_RequestOrConfirm_t RequestOrConfirm); -static void Tst_WriteQstAndAnsSeeing (struct TstExa_Exam *Exam, +static void Tst_WriteQstAndAnsSeeing (const struct TstExa_Exam *Exam, unsigned NumQst, - struct Tst_Question *Question, - MYSQL_ROW row); + const struct Tst_Question *Question, + const char *Stem); static void Tst_PutFormToEditQstMedia (const struct Media *Media,int NumMediaInForm, bool OptionsDisabled); @@ -185,8 +185,8 @@ static void Tst_GetQuestions (struct Tst_Test *Test,MYSQL_RES **mysql_res); static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test, struct TstExa_Exam *Exam); static void Tst_GenerateChoiceIndexesDependingOnShuffle (struct TstExa_Exam *Exam, - unsigned NumQst, - bool Shuffle); + unsigned NumQst, + bool Shuffle); static void Tst_ListOneQstToEdit (struct Tst_Test *Test); static void Tst_ListOneOrMoreQuestionsForEdition (struct Tst_Test *Test, @@ -198,31 +198,26 @@ static void Tst_ListOneOrMoreQuestionsForSelection (unsigned NumQsts, static void Tst_WriteQuestionRowForSelection (unsigned NumQst, struct Tst_Question *Question); -static void Tst_WriteAnswersSeeing (struct TstExa_Exam *Exam, +static void Tst_WriteAnswersSeeing (const struct TstExa_Exam *Exam, unsigned NumQst, - struct Tst_Question *Question); + const struct Tst_Question *Question); -static void Tst_WriteIntAnsListing (const struct Tst_Question *Question, - MYSQL_RES *mysql_res); +static void Tst_WriteIntAnsListing (const struct Tst_Question *Question); static void Tst_WriteIntAnsSeeing (const struct TstExa_Exam *Exam, unsigned NumQst); -static void Tst_WriteFloatAnsEdit (const struct Tst_Question *Question, - MYSQL_RES *mysql_res); +static void Tst_WriteFloatAnsEdit (const struct Tst_Question *Question); static void Tst_WriteFloatAnsSeeing (const struct TstExa_Exam *Exam, unsigned NumQst); -static void Tst_WriteTFAnsListing (const struct Tst_Question *Question, - MYSQL_RES *mysql_res); +static void Tst_WriteTFAnsListing (const struct Tst_Question *Question); static void Tst_WriteTFAnsSeeing (const struct TstExa_Exam *Exam, unsigned NumQst); -static void Tst_WriteChoiceAnsListing (struct Tst_Question *Question, - MYSQL_RES *mysql_res); +static void Tst_WriteChoiceAnsListing (const struct Tst_Question *Question); static void Tst_WriteChoiceAnsSeeing (const struct TstExa_Exam *Exam, unsigned NumQst, - struct Tst_Question *Question, - MYSQL_RES *mysql_res); + const struct Tst_Question *Question); static void Tst_WriteTextAnsSeeing (const struct TstExa_Exam *Exam, unsigned NumQst); @@ -870,11 +865,10 @@ static void Tst_ShowTestExamToFillIt (struct TstExa_Exam *Exam, { extern const char *Hlp_ASSESSMENT_Tests; extern const char *Txt_Test; - // extern const char *Txt_Done_assess_test; - MYSQL_RES *mysql_res; - MYSQL_ROW row; unsigned NumQst; struct Tst_Question Question; + char Stem[Cns_MAX_BYTES_TEXT + 1]; + char Feedback[Cns_MAX_BYTES_TEXT + 1]; static const Act_Action_t Action[Tst_NUM_REQUEST_OR_CONFIRM] = { [Tst_REQUEST] = ActReqAssTst, @@ -912,17 +906,12 @@ static void Tst_ShowTestExamToFillIt (struct TstExa_Exam *Exam, Question.QstCod = Exam->Questions[NumQst].QstCod; /* Show question */ - if (Tst_GetOneQuestionByCod (Question.QstCod,&mysql_res)) // Question exists - { - /* Get row of the result of the query */ - row = mysql_fetch_row (mysql_res); - - /* Write question and answers */ - Tst_WriteQstAndAnsSeeing (Exam,NumQst,&Question,row); - } - else + if (!Tst_GetQstDataFromDB (&Question,Stem,Feedback)) // Question exists Lay_ShowErrorAndExit ("Wrong question."); + /* Write question and answers */ + Tst_WriteQstAndAnsSeeing (Exam,NumQst,&Question,Stem); + /* Destroy test question */ Tst_QstDestructor (&Question); } @@ -985,30 +974,17 @@ void Tst_ShowTagList (unsigned NumTags,MYSQL_RES *mysql_res) /********** Write a row of a test, with one question and its answer **********/ /*****************************************************************************/ -static void Tst_WriteQstAndAnsSeeing (struct TstExa_Exam *Exam, +static void Tst_WriteQstAndAnsSeeing (const struct TstExa_Exam *Exam, unsigned NumQst, - struct Tst_Question *Question, - MYSQL_ROW row) + const struct Tst_Question *Question, + const char *Stem) { - /* - row[0] UNIX_TIMESTAMP(EditTime) - row[1] AnsType - row[2] Shuffle - row[3] Stem - row[4] Feedback - row[5] MedCod - row[6] NumHits - row[7] NumHitsNotBlank - row[8] Score - */ - /***** Begin row *****/ HTM_TR_Begin (NULL); - /***** Number of question and answer type (row[1]) *****/ + /***** Number of question and answer type *****/ HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); Tst_WriteNumQst (NumQst + 1); - Question->Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); Tst_WriteAnswerType (Question->Answer.Type); HTM_TD_End (); @@ -1018,12 +994,10 @@ static void Tst_WriteQstAndAnsSeeing (struct TstExa_Exam *Exam, /* Write parameter with question code */ Tst_WriteParamQstCod (NumQst,Question->QstCod); - /* Stem (row[3]) */ - Tst_WriteQstStem (row[3],"TEST_EXA",true); + /* Stem */ + Tst_WriteQstStem (Stem,"TEST_EXA",true); - /* Media (row[5]) */ - Question->Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); - Med_GetMediaDataByCod (&Question->Media); + /* Media */ Med_ShowMedia (&Question->Media, "TEST_MED_SHOW_CONT", "TEST_MED_SHOW"); @@ -2613,8 +2587,8 @@ static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test, /*****************************************************************************/ static void Tst_GenerateChoiceIndexesDependingOnShuffle (struct TstExa_Exam *Exam, - unsigned NumQst, - bool Shuffle) + unsigned NumQst, + bool Shuffle) { extern const char *Par_SEPARATOR_PARAM_MULTIPLE; struct Tst_Question Question; @@ -2709,29 +2683,6 @@ static void Tst_ListOneQstToEdit (struct Tst_Test *Test) Box_BoxEnd (); } -/*****************************************************************************/ -/*********************** Get data of one test question ***********************/ -/*****************************************************************************/ -// Return true on success, false on error - -bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res) - { - /***** Get data of a question from database *****/ - return (DB_QuerySELECT (mysql_res,"can not get data of a question", - "SELECT UNIX_TIMESTAMP(EditTime)," // row[0] - "AnsType," // row[1] - "Shuffle," // row[2] - "Stem," // row[3] - "Feedback," // row[4] - "MedCod," // row[5] - "NumHits," // row[6] - "NumHitsNotBlank," // row[7] - "Score" // row[8] - " FROM tst_questions" - " WHERE QstCod=%ld", - QstCod) == 1); - } - /*****************************************************************************/ /****************** List for edition one or more test questions **************/ /*****************************************************************************/ @@ -2853,32 +2804,14 @@ static void Tst_WriteHeadingRowQuestionsForEdition (const struct Tst_Test *Test) static void Tst_WriteQuestionListing (struct Tst_Test *Test,unsigned NumQst) { - MYSQL_RES *mysql_res; - MYSQL_ROW row; static unsigned UniqueId = 0; char *Id; - time_t TimeUTC; - unsigned long NumHitsThisQst; - unsigned long NumHitsNotBlankThisQst; - double Score; + char Stem[Cns_MAX_BYTES_TEXT + 1]; + char Feedback[Cns_MAX_BYTES_TEXT + 1]; /***** Get and show question data *****/ - if (Tst_GetOneQuestionByCod (Test->Question.QstCod,&mysql_res)) + if (Tst_GetQstDataFromDB (&Test->Question,Stem,Feedback)) { - /***** Get row from database *****/ - row = mysql_fetch_row (mysql_res); - /* - row[0] UNIX_TIMESTAMP(EditTime) - row[1] AnsType - row[2] Shuffle - row[3] Stem - row[4] Feedback - row[5] MedCod - row[6] NumHits - row[7] NumHitsNotBlank - row[8] Score - */ - /***** Begin table row *****/ HTM_TR_Begin (NULL); @@ -2901,10 +2834,9 @@ static void Tst_WriteQuestionListing (struct Tst_Test *Test,unsigned NumQst) HTM_TD_End (); - /* Number of question and answer type (row[1]) */ + /* Number of question and answer type */ HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); Tst_WriteNumQst (NumQst + 1); - Test->Question.Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); Tst_WriteAnswerType (Test->Question.Answer.Type); HTM_TD_End (); @@ -2914,12 +2846,11 @@ static void Tst_WriteQuestionListing (struct Tst_Test *Test,unsigned NumQst) HTM_TD_End (); /* Date (row[0] has the UTC date-time) */ - TimeUTC = Dat_GetUNIXTimeFromStr (row[0]); if (asprintf (&Id,"tst_date_%u",++UniqueId) < 0) Lay_NotEnoughMemoryExit (); HTM_TD_Begin ("id=\"%s\" class=\"DAT_SMALL CT COLOR%u\"", Id,Gbl.RowEvenOdd); - Dat_WriteLocalDateHMSFromUTC (Id,TimeUTC, + Dat_WriteLocalDateHMSFromUTC (Id,Test->Question.EditTime, Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK, true,true,false,0x7); HTM_TD_End (); @@ -2944,69 +2875,49 @@ static void Tst_WriteQuestionListing (struct Tst_Test *Test,unsigned NumQst) Par_PutHiddenParamUnsigned (NULL,"Order",(unsigned) Test->SelectedOrder); HTM_INPUT_CHECKBOX ("Shuffle",HTM_SUBMIT_ON_CHANGE, "value=\"Y\"%s", - row[2][0] == 'Y' ? " checked=\"checked\"" : - ""); + Test->Question.Answer.Shuffle ? " checked=\"checked\"" : + ""); Frm_EndForm (); } HTM_TD_End (); /* Stem (row[3]) */ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); - Tst_WriteQstStem (row[3],"TEST_EDI", + Tst_WriteQstStem (Stem,"TEST_EDI", true); // Visible /***** Get and show media (row[5]) *****/ - Test->Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); - Med_GetMediaDataByCod (&Test->Question.Media); Med_ShowMedia (&Test->Question.Media, "TEST_MED_EDIT_LIST_CONT", "TEST_MED_EDIT_LIST"); /* Feedback (row[4]) and answers */ - Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT"); + Tst_WriteQstFeedback (Feedback,"TEST_EDI_LIGHT"); Tst_WriteAnswersListing (&Test->Question); HTM_TD_End (); - /* Get number of hits - (number of times that the question has been answered, - including blank answers) (row[6]) */ - if (sscanf (row[6],"%lu",&NumHitsThisQst) != 1) - Lay_ShowErrorAndExit ("Wrong number of hits to a question."); - - /* Get number of hits not blank - (number of times that the question has been answered - with a not blank answer) (row[7]) */ - if (sscanf (row[7],"%lu",&NumHitsNotBlankThisQst) != 1) - Lay_ShowErrorAndExit ("Wrong number of hits not blank to a question."); - - /* Get the acumulated score of the question (row[8]) */ - Str_SetDecimalPointToUS (); // To get the decimal point as a dot - if (sscanf (row[8],"%lf",&Score) != 1) - Lay_ShowErrorAndExit ("Wrong score of a question."); - Str_SetDecimalPointToLocal (); // Return to local system - /* Number of times this question has been answered */ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); - HTM_UnsignedLong (NumHitsThisQst); + HTM_UnsignedLong (Test->Question.NumHits); HTM_TD_End (); /* Average score */ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); - if (NumHitsThisQst) - HTM_Double2Decimals (Score / (double) NumHitsThisQst); + if (Test->Question.NumHits) + HTM_Double2Decimals (Test->Question.Score / (double) Test->Question.NumHits); else HTM_Txt ("N.A."); HTM_TD_End (); /* Number of times this question has been answered (not blank) */ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); - HTM_UnsignedLong (NumHitsNotBlankThisQst); + HTM_UnsignedLong (Test->Question.NumHitsNotBlank); HTM_TD_End (); /* Average score (not blank) */ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); - if (NumHitsNotBlankThisQst) - HTM_Double2Decimals (Score / (double) NumHitsNotBlankThisQst); + if (Test->Question.NumHitsNotBlank) + HTM_Double2Decimals (Test->Question.Score / (double) Test->Question.NumHitsNotBlank); else HTM_Txt ("N.A."); HTM_TD_End (); @@ -3014,9 +2925,6 @@ static void Tst_WriteQuestionListing (struct Tst_Test *Test,unsigned NumQst) /***** End table row *****/ HTM_TR_End (); } - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ @@ -3108,29 +3016,14 @@ static void Tst_WriteQuestionRowForSelection (unsigned NumQst, struct Tst_Question *Question) { extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES]; - MYSQL_RES *mysql_res; - MYSQL_ROW row; + char Stem[Cns_MAX_BYTES_TEXT + 1]; + char Feedback[Cns_MAX_BYTES_TEXT + 1]; static unsigned UniqueId = 0; char *Id; - time_t TimeUTC; /***** Get and show questvoidion data *****/ - if (Tst_GetOneQuestionByCod (Question->QstCod,&mysql_res)) + if (Tst_GetQstDataFromDB (Question,Stem,Feedback)) { - /***** Get row of the result of the query *****/ - row = mysql_fetch_row (mysql_res); - /* - row[0] UNIX_TIMESTAMP(EditTime) - row[1] AnsType - row[2] Shuffle - row[3] Stem - row[4] Feedback - row[5] MedCod - row[6] NumHits - row[7] NumHitsNotBlank - row[8] Score - */ - /***** Begin table row *****/ HTM_TR_Begin (NULL); @@ -3153,12 +3046,11 @@ static void Tst_WriteQuestionRowForSelection (unsigned NumQst, HTM_TD_End (); /* Write the date (row[0] has the UTC date-time) */ - TimeUTC = Dat_GetUNIXTimeFromStr (row[0]); if (asprintf (&Id,"tst_date_%u",++UniqueId) < 0) Lay_NotEnoughMemoryExit (); HTM_TD_Begin ("id=\"%s\" class=\"DAT_SMALL CT COLOR%u\">", Id,Gbl.RowEvenOdd); - Dat_WriteLocalDateHMSFromUTC (Id,TimeUTC, + Dat_WriteLocalDateHMSFromUTC (Id,Question->EditTime, Gbl.Prefs.DateFormat,Dat_SEPARATOR_BREAK, true,true,false,0x7); HTM_TD_End (); @@ -3169,34 +3061,31 @@ static void Tst_WriteQuestionRowForSelection (unsigned NumQst, Tst_GetAndWriteTagsQst (Question->QstCod); HTM_TD_End (); - /* Write the question type (row[1]) */ - Question->Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); + /* Write the question type */ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); HTM_TxtF ("%s ",Txt_TST_STR_ANSWER_TYPES[Question->Answer.Type]); HTM_TD_End (); - /* Write if shuffle is enabled (row[2]) */ + /* Write if shuffle is enabled */ HTM_TD_Begin ("class=\"DAT_SMALL CT COLOR%u\"",Gbl.RowEvenOdd); HTM_INPUT_CHECKBOX ("Shuffle",HTM_DONT_SUBMIT_ON_CHANGE, "value=\"Y\"%s disabled=\"disabled\"", - row[2][0] == 'Y' ? " checked=\"checked\"" : - ""); + Question->Answer.Shuffle ? " checked=\"checked\"" : + ""); HTM_TD_End (); - /* Write stem (row[3]) */ + /* Write stem */ HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); - Tst_WriteQstStem (row[3],"TEST_EDI", + Tst_WriteQstStem (Stem,"TEST_EDI", true); // Visible - /***** Get and show media (row[5]) *****/ - Question->Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); - Med_GetMediaDataByCod (&Question->Media); + /***** Get and show media *****/ Med_ShowMedia (&Question->Media, "TEST_MED_EDIT_LIST_CONT", "TEST_MED_EDIT_LIST"); - /* Write feedback (row[4]) */ - Tst_WriteQstFeedback (row[4],"TEST_EDI_LIGHT"); + /* Write feedback */ + Tst_WriteQstFeedback (Feedback,"TEST_EDI_LIGHT"); /* Write answers */ Tst_WriteAnswersListing (Question); @@ -3260,56 +3149,38 @@ void Tst_GetAnswersQst (struct Tst_Question *Question,MYSQL_RES **mysql_res, /**************** Get and write the answers of a test question ***************/ /*****************************************************************************/ -void Tst_WriteAnswersListing (struct Tst_Question *Question) +void Tst_WriteAnswersListing (const struct Tst_Question *Question) { - MYSQL_RES *mysql_res; - - /***** Get answers *****/ - Tst_GetAnswersQst (Question,&mysql_res, - false); // Don't shuffle - /* - row[0] AnsInd - row[1] Answer - row[2] Feedback - row[3] MedCod - row[4] Correct - */ - /***** Write answers *****/ switch (Question->Answer.Type) { case Tst_ANS_INT: - Tst_WriteIntAnsListing (Question,mysql_res); + Tst_WriteIntAnsListing (Question); break; case Tst_ANS_FLOAT: - Tst_WriteFloatAnsEdit (Question,mysql_res); + Tst_WriteFloatAnsEdit (Question); break; case Tst_ANS_TRUE_FALSE: - Tst_WriteTFAnsListing (Question,mysql_res); + Tst_WriteTFAnsListing (Question); break; case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE: case Tst_ANS_TEXT: - Tst_WriteChoiceAnsListing (Question,mysql_res); + Tst_WriteChoiceAnsListing (Question); break; default: break; } - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ /************** Write answers of a question when seeing a test ***************/ /*****************************************************************************/ -static void Tst_WriteAnswersSeeing (struct TstExa_Exam *Exam, +static void Tst_WriteAnswersSeeing (const struct TstExa_Exam *Exam, unsigned NumQst, - struct Tst_Question *Question) + const struct Tst_Question *Question) { - MYSQL_RES *mysql_res; - /***** Write answer depending on type *****/ switch (Question->Answer.Type) { @@ -3324,15 +3195,7 @@ static void Tst_WriteAnswersSeeing (struct TstExa_Exam *Exam, break; case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE: - /* Get answer of a question from database */ - Tst_GetAnswersQst (Question,&mysql_res, - false); // Don't shuffle - - /* Write answer */ - Tst_WriteChoiceAnsSeeing (Exam,NumQst,Question,mysql_res); - - /* Free structure that stores the query result */ - DB_FreeMySQLResult (&mysql_res); + Tst_WriteChoiceAnsSeeing (Exam,NumQst,Question); break; case Tst_ANS_TEXT: Tst_WriteTextAnsSeeing (Exam,NumQst); @@ -3360,22 +3223,10 @@ bool Tst_CheckIfQuestionIsValidForGame (long QstCod) /****************** Write integer answer when editing a test *****************/ /*****************************************************************************/ -static void Tst_WriteIntAnsListing (const struct Tst_Question *Question, - MYSQL_RES *mysql_res) +static void Tst_WriteIntAnsListing (const struct Tst_Question *Question) { - MYSQL_ROW row; - /* - row[0] AnsInd - row[1] Answer - row[2] Feedback - row[3] MedCod - row[4] Correct - */ - - Tst_CheckIfNumberOfAnswersIsOne (Question); - row = mysql_fetch_row (mysql_res); HTM_SPAN_Begin ("class=\"TEST_EDI\""); - HTM_TxtF ("(%ld)",Tst_GetIntAnsFromStr (row[1])); + HTM_TxtF ("(%ld)",Question->Answer.Integer); HTM_SPAN_End (); } @@ -3400,35 +3251,13 @@ static void Tst_WriteIntAnsSeeing (const struct TstExa_Exam *Exam, /****************** Write float answer when editing a test *******************/ /*****************************************************************************/ -static void Tst_WriteFloatAnsEdit (const struct Tst_Question *Question, - MYSQL_RES *mysql_res) +static void Tst_WriteFloatAnsEdit (const struct Tst_Question *Question) { - MYSQL_ROW row; - unsigned i; - double FloatNum[2]; - /* - row[0] AnsInd - row[1] Answer - row[2] Feedback - row[3] MedCod - row[4] Correct - */ - - if (Question->Answer.NumOptions != 2) - Lay_ShowErrorAndExit ("Wrong float range."); - - for (i = 0; - i < 2; - i++) - { - row = mysql_fetch_row (mysql_res); - FloatNum[i] = Str_GetDoubleFromStr (row[1]); - } HTM_SPAN_Begin ("class=\"TEST_EDI\""); HTM_Txt ("(["); - HTM_Double (FloatNum[0]); + HTM_Double (Question->Answer.FloatingPoint[0]); HTM_Txt ("; "); - HTM_Double (FloatNum[1]); + HTM_Double (Question->Answer.FloatingPoint[1]); HTM_Txt ("])"); HTM_SPAN_End (); } @@ -3454,27 +3283,12 @@ static void Tst_WriteFloatAnsSeeing (const struct TstExa_Exam *Exam, /*********** Write false / true answer when listing test questions ***********/ /*****************************************************************************/ -static void Tst_WriteTFAnsListing (const struct Tst_Question *Question, - MYSQL_RES *mysql_res) +static void Tst_WriteTFAnsListing (const struct Tst_Question *Question) { - MYSQL_ROW row; - /* - row[0] AnsInd - row[1] Answer - row[2] Feedback - row[3] MedCod - row[4] Correct - */ - - Tst_CheckIfNumberOfAnswersIsOne (Question); - - /***** Get answer true or false *****/ - row = mysql_fetch_row (mysql_res); - /***** Write answer *****/ HTM_SPAN_Begin ("class=\"TEST_EDI\""); HTM_Txt ("("); - Tst_WriteAnsTF (row[1][0]); + Tst_WriteAnsTF (Question->Answer.TF); HTM_Txt (")"); HTM_SPAN_End (); } @@ -3526,65 +3340,55 @@ void Tst_WriteAnsTF (char AnsTF) /**** Write single or multiple choice answer when listing test questions *****/ /*****************************************************************************/ -static void Tst_WriteChoiceAnsListing (struct Tst_Question *Question, - MYSQL_RES *mysql_res) +static void Tst_WriteChoiceAnsListing (const struct Tst_Question *Question) { extern const char *Txt_TST_Answer_given_by_the_teachers; - MYSQL_ROW row; unsigned NumOpt; char *AnswerTxt; char *Feedback; size_t LengthAnswerTxt; size_t LengthFeedback; - /* - row[0] AnsInd - row[1] Answer - row[2] Feedback - row[3] MedCod - row[4] Correct - */ HTM_TABLE_BeginPadding (2); for (NumOpt = 0; NumOpt < Question->Answer.NumOptions; NumOpt++) { - row = mysql_fetch_row (mysql_res); + /* Convert the answer, that is in HTML, to rigorous HTML */ + LengthAnswerTxt = 0; + AnswerTxt = NULL; + if (Question->Answer.Options[NumOpt].Text) + if (Question->Answer.Options[NumOpt].Text[0]) + { + LengthAnswerTxt = strlen (Question->Answer.Options[NumOpt].Text) * Str_MAX_BYTES_PER_CHAR; + if ((AnswerTxt = (char *) malloc (LengthAnswerTxt + 1)) == NULL) + Lay_NotEnoughMemoryExit (); + Str_Copy (AnswerTxt,Question->Answer.Options[NumOpt].Text, + LengthAnswerTxt); + Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, + AnswerTxt,LengthAnswerTxt,false); + } - /* Convert the answer (row[1]), that is in HTML, to rigorous HTML */ - LengthAnswerTxt = strlen (row[1]) * Str_MAX_BYTES_PER_CHAR; - if ((AnswerTxt = (char *) malloc (LengthAnswerTxt + 1)) == NULL) - Lay_NotEnoughMemoryExit (); - Str_Copy (AnswerTxt,row[1], - LengthAnswerTxt); - Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, - AnswerTxt,LengthAnswerTxt,false); - - /* Convert the feedback (row[2]), that is in HTML, to rigorous HTML */ + /* Convert the feedback, that is in HTML, to rigorous HTML */ LengthFeedback = 0; Feedback = NULL; - if (row[2]) - if (row[2][0]) + if (Question->Answer.Options[NumOpt].Feedback) + if (Question->Answer.Options[NumOpt].Feedback[0]) { - LengthFeedback = strlen (row[2]) * Str_MAX_BYTES_PER_CHAR; + LengthFeedback = strlen (Question->Answer.Options[NumOpt].Feedback) * Str_MAX_BYTES_PER_CHAR; if ((Feedback = (char *) malloc (LengthFeedback + 1)) == NULL) Lay_NotEnoughMemoryExit (); - Str_Copy (Feedback,row[2], + Str_Copy (Feedback,Question->Answer.Options[NumOpt].Feedback, LengthFeedback); Str_ChangeFormat (Str_FROM_HTML,Str_TO_RIGOROUS_HTML, Feedback,LengthFeedback,false); } - /* Get media (row[3]) */ - Question->Answer.Options[NumOpt].Media.MedCod = Str_ConvertStrCodToLongCod (row[3]); - Med_GetMediaDataByCod (&Question->Answer.Options[NumOpt].Media); - HTM_TR_Begin (NULL); - /* Put an icon that indicates whether the answer - is correct or wrong (row[4]) */ + /* Put an icon that indicates whether the answer is correct or wrong */ HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd); - if (row[4][0] == 'Y') + if (Question->Answer.Options[NumOpt].Correct) Ico_PutIcon ("check.svg",Txt_TST_Answer_given_by_the_teachers,"CONTEXT_ICO_16x16"); HTM_TD_End (); @@ -3597,7 +3401,8 @@ static void Tst_WriteChoiceAnsListing (struct Tst_Question *Question, /* Write the text of the answer and the media */ HTM_DIV_Begin ("class=\"TEST_EDI\""); - HTM_Txt (AnswerTxt); + if (LengthAnswerTxt) + HTM_Txt (AnswerTxt); Med_ShowMedia (&Question->Answer.Options[NumOpt].Media, "TEST_MED_EDIT_LIST_CONT", "TEST_MED_EDIT_LIST"); @@ -3627,23 +3432,12 @@ static void Tst_WriteChoiceAnsListing (struct Tst_Question *Question, static void Tst_WriteChoiceAnsSeeing (const struct TstExa_Exam *Exam, unsigned NumQst, - struct Tst_Question *Question, - MYSQL_RES *mysql_res) + const struct Tst_Question *Question) { unsigned NumOpt; unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; // Indexes of all answers of this question bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION]; char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x" - /* - row[0] AnsInd - row[1] Answer - row[2] Feedback - row[3] MedCod - row[4] Correct - */ - /***** Get text and correctness of answers for this question - from database (one row per answer) *****/ - Tst_GetChoiceAns (Question,mysql_res); /***** Get indexes for this question from string *****/ TstExa_GetIndexesFromStr (Exam->Questions[NumQst].StrIndexes,Indexes); @@ -4041,9 +3835,11 @@ static int Tst_CountNumAnswerTypesInList (const struct Tst_AnswerTypes *AnswerTy void Tst_ShowFormEditOneQst (void) { + extern const char *Txt_Question_removed; struct Tst_Question Question; char Stem[Cns_MAX_BYTES_TEXT + 1]; char Feedback[Cns_MAX_BYTES_TEXT + 1]; + bool PutFormToEditQuestion; /***** Create test question *****/ Tst_QstConstructor (&Question); @@ -4051,11 +3847,16 @@ void Tst_ShowFormEditOneQst (void) /***** Get question data *****/ Question.QstCod = Tst_GetQstCod (); Stem[0] = Feedback[0] = '\0'; - if (Question.QstCod > 0) // If question already exists in the database - Tst_GetQstDataFromDB (&Question,Stem,Feedback); + if (Question.QstCod > 0) // Question already exists in the database + PutFormToEditQuestion = Tst_GetQstDataFromDB (&Question,Stem,Feedback); + else // New question + PutFormToEditQuestion = true; /***** Put form to edit question *****/ - Tst_PutFormEditOneQst (&Question,Stem,Feedback); + if (PutFormToEditQuestion) + Tst_PutFormEditOneQst (&Question,Stem,Feedback); + else + Ale_ShowAlert (Ale_WARNING,Txt_Question_removed); /***** Destroy test question *****/ Tst_QstDestructor (&Question); @@ -4565,6 +4366,11 @@ void Tst_QstConstructor (struct Tst_Question *Question) Question->Answer.Integer = 0; Question->Answer.FloatingPoint[0] = Question->Answer.FloatingPoint[1] = 0.0; + + /* Initialize stats */ + Question->NumHits = + Question->NumHitsNotBlank = 0; + Question->Score = 0.0; } /*****************************************************************************/ @@ -4701,9 +4507,8 @@ Tst_AnswerType_t Tst_GetQstAnswerType (long QstCod) /*****************************************************************************/ /****************** Get data of a question from database *********************/ /*****************************************************************************/ -// If question does not exist ==> set question code to -1 -void Tst_GetQstDataFromDB (struct Tst_Question *Question, +bool Tst_GetQstDataFromDB (struct Tst_Question *Question, char Stem[Cns_MAX_BYTES_TEXT + 1], char Feedback[Cns_MAX_BYTES_TEXT + 1]) { @@ -4721,7 +4526,10 @@ void Tst_GetQstDataFromDB (struct Tst_Question *Question, "Shuffle," // row[2] "Stem," // row[3] "Feedback," // row[4] - "MedCod" // row[5] + "MedCod," // row[5] + "NumHits," // row[6] + "NumHitsNotBlank," // row[7] + "Score" // row[8] " FROM tst_questions" " WHERE QstCod=%ld" " AND CrsCod=%ld", // Extra check @@ -4759,6 +4567,24 @@ void Tst_GetQstDataFromDB (struct Tst_Question *Question, Question->Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); Med_GetMediaDataByCod (&Question->Media); + /* Get number of hits + (number of times that the question has been answered, + including blank answers) (row[6]) */ + if (sscanf (row[6],"%lu",&Question->NumHits) != 1) + Question->NumHits = 0; + + /* Get number of hits not blank + (number of times that the question has been answered + with a not blank answer) (row[7]) */ + if (sscanf (row[7],"%lu",&Question->NumHitsNotBlank) != 1) + Question->NumHitsNotBlank = 0; + + /* Get the acumulated score of the question (row[8]) */ + Str_SetDecimalPointToUS (); // To get the decimal point as a dot + if (sscanf (row[8],"%lf",&Question->Score) != 1) + Question->Score = 0.0; + Str_SetDecimalPointToLocal (); // Return to local system + /* Free structure that stores the query result */ DB_FreeMySQLResult (&mysql_res); @@ -4844,11 +4670,11 @@ void Tst_GetQstDataFromDB (struct Tst_Question *Question, } } } - else - Question->QstCod = -1L; /* Free structure that stores the query result */ DB_FreeMySQLResult (&mysql_res); + + return QuestionExists; } /*****************************************************************************/ diff --git a/swad_test.h b/swad_test.h index 7e91a382..98da605b 100644 --- a/swad_test.h +++ b/swad_test.h @@ -117,6 +117,9 @@ struct Tst_Question long Integer; double FloatingPoint[2]; } Answer; + unsigned long NumHits; + unsigned long NumHitsNotBlank; + double Score; }; struct Tst_Test @@ -170,13 +173,12 @@ void Tst_RequestSelectTestsForGame (void); void Tst_ListQuestionsToEdit (void); void Tst_ListQuestionsToSelect (void); -bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res); void Tst_WriteParamEditQst (const struct Tst_Test *Test); unsigned Tst_GetNumAnswersQst (long QstCod); void Tst_GetAnswersQst (struct Tst_Question *Question,MYSQL_RES **mysql_res, bool Shuffle); -void Tst_WriteAnswersListing (struct Tst_Question *Question); +void Tst_WriteAnswersListing (const struct Tst_Question *Question); bool Tst_CheckIfQuestionIsValidForGame (long QstCod); void Tst_WriteAnsTF (char AnsTF); void Tst_GetChoiceAns (struct Tst_Question *Question,MYSQL_RES *mysql_res); @@ -200,7 +202,7 @@ void Tst_QstDestructor (struct Tst_Question *Question); bool Tst_AllocateTextChoiceAnswer (struct Tst_Question *Question,unsigned NumOpt); Tst_AnswerType_t Tst_GetQstAnswerType (long QstCod); -void Tst_GetQstDataFromDB (struct Tst_Question *Question, +bool Tst_GetQstDataFromDB (struct Tst_Question *Question, char Stem[Cns_MAX_BYTES_TEXT + 1], char Feedback[Cns_MAX_BYTES_TEXT + 1]); Tst_AnswerType_t Tst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD); diff --git a/swad_test_exam.c b/swad_test_exam.c index b68a7e8c..ae004ec2 100644 --- a/swad_test_exam.c +++ b/swad_test_exam.c @@ -245,8 +245,7 @@ void TstExa_ShowExamAfterAssess (struct TstExa_Exam *Exam) Question.QstCod = Exam->Questions[NumQst].QstCod; /***** Get question data *****/ - Tst_GetQstDataFromDB (&Question,Stem,Feedback); - if (Question.QstCod > 0) // Question exists + if (Tst_GetQstDataFromDB (&Question,Stem,Feedback)) // Question exists { /***** Write question and answers *****/ TstExa_WriteQstAndAnsExam (&Gbl.Usrs.Me.UsrDat, @@ -2218,13 +2217,12 @@ void TstExa_ShowExamAnswers (struct UsrData *UsrDat, Question.QstCod = Exam->Questions[NumQst].QstCod; /***** Get question data *****/ - Tst_GetQstDataFromDB (&Question,Stem,Feedback); - - /***** Write questions and answers *****/ - TstExa_WriteQstAndAnsExam (UsrDat, - Exam,NumQst, - &Question,Stem,Feedback, - Visibility); + if (Tst_GetQstDataFromDB (&Question,Stem,Feedback)) // Question exists? + /***** Write questions and answers *****/ + TstExa_WriteQstAndAnsExam (UsrDat, + Exam,NumQst, + &Question,Stem,Feedback, + Visibility); /***** Destroy test question *****/ Tst_QstDestructor (&Question); diff --git a/swad_test_import.c b/swad_test_import.c index 072a64e3..24686919 100644 --- a/swad_test_import.c +++ b/swad_test_import.c @@ -71,7 +71,7 @@ static void TsI_PutCreateXMLParam (void); static void TsI_ExportQuestion (struct Tst_Question *Question,FILE *FileXML); static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML); -static void TsI_WriteAnswersOfAQstXML (struct Tst_Question *Question, +static void TsI_WriteAnswersOfAQstXML (const struct Tst_Question *Question, FILE *FileXML); static void TsI_ReadQuestionsFromXMLFileAndStoreInDB (const char *FileNameXML); static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer); @@ -259,27 +259,12 @@ static void TsI_ExportQuestion (struct Tst_Question *Question,FILE *FileXML) { extern const char *Tst_StrAnswerTypesXML[Tst_NUM_ANS_TYPES]; extern const char *Txt_NEW_LINE; - MYSQL_RES *mysql_res; - MYSQL_ROW row; + char Stem[Cns_MAX_BYTES_TEXT + 1]; + char Feedback[Cns_MAX_BYTES_TEXT + 1]; - if (Tst_GetOneQuestionByCod (Question->QstCod,&mysql_res)) + if (Tst_GetQstDataFromDB (Question,Stem,Feedback)) { - /***** Get row *****/ - row = mysql_fetch_row (mysql_res); - /* - row[0] UNIX_TIMESTAMP(EditTime) - row[1] AnsType - row[2] Shuffle - row[3] Stem - row[4] Feedback - row[5] MedCod - row[6] NumHits - row[7] NumHitsNotBlank - row[8] Score - */ - - /***** Write the answer type (row[1]) *****/ - Question->Answer.Type = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]); + /***** Write the answer type *****/ fprintf (FileXML,"%s", Tst_StrAnswerTypesXML[Question->Answer.Type],Txt_NEW_LINE); @@ -288,24 +273,23 @@ static void TsI_ExportQuestion (struct Tst_Question *Question,FILE *FileXML) TsI_GetAndWriteTagsXML (Question->QstCod,FileXML); fprintf (FileXML,"%s",Txt_NEW_LINE); - /***** Write the stem (row[3]), that is in HTML format *****/ + /***** Write the stem, that is in HTML format *****/ fprintf (FileXML,"%s%s", - row[3],Txt_NEW_LINE); + Stem,Txt_NEW_LINE); - /***** Write the feedback (row[4]), that is in HTML format *****/ - if (row[4]) - if (row[4][0]) - fprintf (FileXML,"%s%s", - row[4],Txt_NEW_LINE); + /***** Write the feedback, that is in HTML format *****/ + if (Feedback[0]) + fprintf (FileXML,"%s%s", + Feedback,Txt_NEW_LINE); /***** Write the answers of this question. - Shuffle can be enabled or disabled (row[2]) *****/ + Shuffle can be enabled or disabled *****/ fprintf (FileXML,"Answer.Type == Tst_ANS_UNIQUE_CHOICE || Question->Answer.Type == Tst_ANS_MULTIPLE_CHOICE) fprintf (FileXML," shuffle=\"%s\"", - (row[2][0] == 'Y') ? "yes" : - "no"); + Question->Answer.Shuffle ? "yes" : + "no"); fprintf (FileXML,">"); TsI_WriteAnswersOfAQstXML (Question,FileXML); fprintf (FileXML,"%s",Txt_NEW_LINE); @@ -347,60 +331,30 @@ static void TsI_GetAndWriteTagsXML (long QstCod,FILE *FileXML) /**************** Get and write the answers of a test question ***************/ /*****************************************************************************/ -static void TsI_WriteAnswersOfAQstXML (struct Tst_Question *Question, +static void TsI_WriteAnswersOfAQstXML (const struct Tst_Question *Question, FILE *FileXML) { extern const char *Txt_NEW_LINE; unsigned NumOpt; - unsigned i; - MYSQL_RES *mysql_res; - MYSQL_ROW row; - double FloatNum[2]; - - /***** Get answers *****/ - Tst_GetAnswersQst (Question,&mysql_res, - false); // Don't shuffle - /* - row[0] AnsInd - row[1] Answer - row[2] Feedback - row[3] MedCod - row[4] Correct - */ /***** Write answers *****/ switch (Question->Answer.Type) { case Tst_ANS_INT: - Tst_CheckIfNumberOfAnswersIsOne (Question); - row = mysql_fetch_row (mysql_res); - fprintf (FileXML,"%ld", - Tst_GetIntAnsFromStr (row[1])); + fprintf (FileXML,"%ld",Question->Answer.Integer); break; case Tst_ANS_FLOAT: - if (Question->Answer.NumOptions != 2) - Lay_ShowErrorAndExit ("Wrong float range."); - - for (i = 0; - i < 2; - i++) - { - row = mysql_fetch_row (mysql_res); - FloatNum[i] = Str_GetDoubleFromStr (row[1]); - } fprintf (FileXML,"%s" "%.15lg%s" "%.15lg%s", Txt_NEW_LINE, - FloatNum[0],Txt_NEW_LINE, - FloatNum[1],Txt_NEW_LINE); + Question->Answer.FloatingPoint[0],Txt_NEW_LINE, + Question->Answer.FloatingPoint[1],Txt_NEW_LINE); break; case Tst_ANS_TRUE_FALSE: - Tst_CheckIfNumberOfAnswersIsOne (Question); - row = mysql_fetch_row (mysql_res); fprintf (FileXML,"%s", - row[1][0] == 'T' ? "true" : - "false"); + Question->Answer.TF == 'T' ? "true" : + "false"); break; case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE: @@ -410,28 +364,26 @@ static void TsI_WriteAnswersOfAQstXML (struct Tst_Question *Question, NumOpt < Question->Answer.NumOptions; NumOpt++) { - row = mysql_fetch_row (mysql_res); - /* Start answer */ fprintf (FileXML,"Answer.Type != Tst_ANS_TEXT) fprintf (FileXML," correct=\"%s\"", - (row[4][0] == 'Y') ? "yes" : - "no"); + Question->Answer.Options[NumOpt].Correct ? "yes" : + "no"); fprintf (FileXML,">%s",Txt_NEW_LINE); - /* Write the answer (row[1]), that is in HTML */ + /* Write the answer, that is in HTML */ fprintf (FileXML,"%s%s", - row[1],Txt_NEW_LINE); + Question->Answer.Options[NumOpt].Text,Txt_NEW_LINE); - /* Write the feedback (row[2]) */ - if (row[2]) - if (row[2][0]) + /* Write the feedback */ + if (Question->Answer.Options[NumOpt].Feedback) + if (Question->Answer.Options[NumOpt].Feedback[0]) fprintf (FileXML,"%s%s", - row[2],Txt_NEW_LINE); + Question->Answer.Options[NumOpt].Feedback,Txt_NEW_LINE); /* End answer */ fprintf (FileXML,"%s", @@ -441,9 +393,6 @@ static void TsI_WriteAnswersOfAQstXML (struct Tst_Question *Question, default: break; } - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); } /*****************************************************************************/ diff --git a/swad_text.c b/swad_text.c index 6299e326..54620394 100644 --- a/swad_text.c +++ b/swad_text.c @@ -9791,27 +9791,6 @@ const char *Txt_Done = "Feito"; #endif -const char *Txt_Done_assess_test = -#if L==1 // ca - "He acabat; corregir test"; -#elif L==2 // de - "Geschehen; beurteilen Test"; -#elif L==3 // en - "Done; assess test"; -#elif L==4 // es - "He terminado; corregir test"; -#elif L==5 // fr - "Fait; corriger test"; -#elif L==6 // gn - "He terminado; corregir test"; // Okoteve traducción -#elif L==7 // it - "Finito; correggere test"; -#elif L==8 // pl - "Sporządzono; oceny test"; -#elif L==9 // pt - "Feito; corrigir teste"; -#endif - const char *Txt_Download = // As a verb #if L==1 // ca "Descarregar";