From 11d934a3cc19afce133e1a942ff72337c2e781a5 Mon Sep 17 00:00:00 2001 From: acanas Date: Tue, 17 Mar 2020 14:47:58 +0100 Subject: [PATCH] Version19.148.3 --- swad_changelog.h | 1 + swad_game.c | 12 ++- swad_global.h | 1 - swad_match.c | 7 +- swad_media.c | 22 ++--- swad_media.h | 2 +- swad_test.c | 231 ++++++++++++++++++++++++++------------------- swad_test.h | 15 +-- swad_test_import.c | 29 +++--- swad_test_result.c | 3 +- 10 files changed, 186 insertions(+), 137 deletions(-) diff --git a/swad_changelog.h b/swad_changelog.h index d0d1bdfcc..4aff4430a 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -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: 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.148.3: Mar 17, 2020 Code refactoring in tests. (282916 lines) Version 19.148.2: Mar 17, 2020 Code refactoring in tests. (282868 lines) Version 19.148.1: Mar 17, 2020 Code refactoring in tests. (282851 lines) Version 19.148: Mar 17, 2020 Code refactoring in tests. diff --git a/swad_game.c b/swad_game.c index a633d038b..c53b101f0 100644 --- a/swad_game.c +++ b/swad_game.c @@ -1874,6 +1874,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, unsigned NumQst; MYSQL_ROW row; long QstCod; + struct Tst_Question Question; unsigned QstInd; unsigned MaxQstInd; char StrQstInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; @@ -1907,7 +1908,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, row[1] QstCod */ /***** Create test question *****/ - Tst_QstConstructor (); + Tst_QstConstructor (&Question); /* Get question index (row[0]) */ QstInd = Str_ConvertStrToUnsigned (row[0]); @@ -1976,7 +1977,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts, HTM_TR_End (); /***** Destroy test question *****/ - Tst_QstDestructor (); + Tst_QstDestructor (&Question); } /***** End table *****/ @@ -1994,6 +1995,7 @@ static void Gam_ListQuestionForEdition (long QstCod,const char *StrQstInd) MYSQL_RES *mysql_res; MYSQL_ROW row; bool QstExists; + struct Media Media; /***** Get question from database *****/ QstExists = Tst_GetOneQuestionByCod (QstCod,&mysql_res); // Question exists? @@ -2054,11 +2056,11 @@ static void Gam_ListQuestionForEdition (long QstCod,const char *StrQstInd) true); // Visible /* Get media (row[5]) */ - Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); - Med_GetMediaDataByCod (&Gbl.Test.Question.Media); + Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); + Med_GetMediaDataByCod (&Media); /* Show media */ - Med_ShowMedia (&Gbl.Test.Question.Media, + Med_ShowMedia (&Media, "TEST_MED_EDIT_LIST_STEM_CONTAINER", "TEST_MED_EDIT_LIST_STEM"); diff --git a/swad_global.h b/swad_global.h index 9eed2ff6e..847d2608d 100644 --- a/swad_global.h +++ b/swad_global.h @@ -666,7 +666,6 @@ struct Globals char StrAnswersOneQst[Tst_MAX_QUESTIONS_PER_TEST][Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user bool AllowTeachers; // Can teachers of this course see the test result? bool AllAnsTypes; - struct Tst_Question Question; struct { unsigned NumOptions; diff --git a/swad_match.c b/swad_match.c index 060401aab..3f24e959d 100644 --- a/swad_match.c +++ b/swad_match.c @@ -2863,6 +2863,7 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match) extern const char *Txt_Question_removed; MYSQL_RES *mysql_res; MYSQL_ROW row; + struct Media Media; /***** Trivial check: do not show anything on match start and end *****/ switch (Match->Status.Showing) @@ -2899,11 +2900,11 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match) true); // Visible /* Get media (row[2]) */ - Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[2]); - Med_GetMediaDataByCod (&Gbl.Test.Question.Media); + Media.MedCod = Str_ConvertStrCodToLongCod (row[2]); + Med_GetMediaDataByCod (&Media); /* Show media */ - Med_ShowMedia (&Gbl.Test.Question.Media, + Med_ShowMedia (&Media, "TEST_MED_EDIT_LIST_STEM_CONTAINER", "TEST_MED_EDIT_LIST_STEM"); diff --git a/swad_media.c b/swad_media.c index 941ec152d..8c6dd5a77 100644 --- a/swad_media.c +++ b/swad_media.c @@ -161,17 +161,17 @@ static bool Med_MoveTmpFileToDefDir (struct Media *Media, const char PathMedPriv[PATH_MAX + 1], const char *Extension); -static void Med_ShowJPG (struct Media *Media, +static void Med_ShowJPG (const struct Media *Media, const char PathMedPriv[PATH_MAX + 1], const char *ClassMedia); -static void Med_ShowGIF (struct Media *Media, +static void Med_ShowGIF (const struct Media *Media, const char PathMedPriv[PATH_MAX + 1], const char *ClassMedia); -static void Med_ShowVideo (struct Media *Media, +static void Med_ShowVideo (const struct Media *Media, const char PathMedPriv[PATH_MAX + 1], const char *ClassMedia); -static void Med_ShowYoutube (struct Media *Media,const char *ClassMedia); -static void Med_ShowEmbed (struct Media *Media,const char *ClassMedia); +static void Med_ShowYoutube (const struct Media *Media,const char *ClassMedia); +static void Med_ShowEmbed (const struct Media *Media,const char *ClassMedia); static void Med_AlertThirdPartyCookies (void); static Med_Type_t Med_GetTypeFromStrInDB (const char *Str); @@ -1426,7 +1426,7 @@ void Med_StoreMediaInDB (struct Media *Media) /****** Show a user uploaded media (in a test question, timeline, etc.) ******/ /*****************************************************************************/ -void Med_ShowMedia (struct Media *Media, +void Med_ShowMedia (const struct Media *Media, const char *ClassContainer,const char *ClassMedia) { bool PutLink; @@ -1515,7 +1515,7 @@ void Med_ShowMedia (struct Media *Media, /************************** Show a user uploaded JPG *************************/ /*****************************************************************************/ -static void Med_ShowJPG (struct Media *Media, +static void Med_ShowJPG (const struct Media *Media, const char PathMedPriv[PATH_MAX + 1], const char *ClassMedia) { @@ -1559,7 +1559,7 @@ static void Med_ShowJPG (struct Media *Media, /************************** Show a user uploaded GIF *************************/ /*****************************************************************************/ -static void Med_ShowGIF (struct Media *Media, +static void Med_ShowGIF (const struct Media *Media, const char PathMedPriv[PATH_MAX + 1], const char *ClassMedia) { @@ -1650,7 +1650,7 @@ static void Med_ShowGIF (struct Media *Media, /************************ Show a user uploaded video *************************/ /*****************************************************************************/ -static void Med_ShowVideo (struct Media *Media, +static void Med_ShowVideo (const struct Media *Media, const char PathMedPriv[PATH_MAX + 1], const char *ClassMedia) { @@ -1704,7 +1704,7 @@ static void Med_ShowVideo (struct Media *Media, /*********************** Show an embed YouTube video *************************/ /*****************************************************************************/ -static void Med_ShowYoutube (struct Media *Media,const char *ClassMedia) +static void Med_ShowYoutube (const struct Media *Media,const char *ClassMedia) { /***** Check if YouTube code exists *****/ if (Media->Name[0]) // YouTube code @@ -1744,7 +1744,7 @@ static void Med_ShowYoutube (struct Media *Media,const char *ClassMedia) /*************************** Show an embed media *****************************/ /*****************************************************************************/ -static void Med_ShowEmbed (struct Media *Media,const char *ClassMedia) +static void Med_ShowEmbed (const struct Media *Media,const char *ClassMedia) { /***** Check if embed URL exists *****/ if (Media->URL[0]) // Embed URL diff --git a/swad_media.h b/swad_media.h index bb05a31e8..075eb5cf6 100644 --- a/swad_media.h +++ b/swad_media.h @@ -150,7 +150,7 @@ void Med_RemoveKeepOrStoreMedia (long CurrentMedCodInDB,struct Media *Media); void Med_MoveMediaToDefinitiveDir (struct Media *Media); void Med_StoreMediaInDB (struct Media *Media); -void Med_ShowMedia (struct Media *Media, +void Med_ShowMedia (const struct Media *Media, const char *ClassContainer,const char *ClassMedia); void Med_RemoveMediaFromAllRows (unsigned NumMedia,MYSQL_RES *mysql_res); diff --git a/swad_test.c b/swad_test.c index 6970b7857..0d962f4a2 100644 --- a/swad_test.c +++ b/swad_test.c @@ -138,7 +138,7 @@ static unsigned Tst_GetNumAccessesTst (void); static void Tst_ShowTestQuestionsWhenSeeing (MYSQL_RES *mysql_res); static void Tst_ShowOneTestQuestionWhenSeeing (unsigned NumQst,long QstCod); static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank,double *TotalScore); -static void Tst_PutFormToEditQstMedia (struct Media *Media,int NumMediaInForm, +static void Tst_PutFormToEditQstMedia (const struct Media *Media,int NumMediaInForm, bool OptionsDisabled); static void Tst_UpdateScoreQst (long QstCod,double ScoreThisQst,bool AnswerIsNotBlank); static void Tst_UpdateMyNumAccessTst (unsigned NumAccessesTst); @@ -221,6 +221,7 @@ static void Tst_GetParamNumQst (void); static int Tst_CountNumTagsInList (void); static int Tst_CountNumAnswerTypesInList (void); static void Tst_PutFormEditOneQst (long QstCod, + const struct Tst_Question *Question, char Stem[Cns_MAX_BYTES_TEXT + 1], char Feedback[Cns_MAX_BYTES_TEXT + 1]); static void Tst_PutFloatInputField (const char *Label,const char *Field, @@ -230,10 +231,11 @@ static void Tst_PutTFInputField (const char *Label,char Value); static void Tst_FreeTextChoiceAnswers (void); static void Tst_FreeTextChoiceAnswer (unsigned NumOpt); -static void Tst_ResetMediaOfQuestion (void); -static void Tst_FreeMediaOfQuestion (void); +static void Tst_ResetMediaOfQuestion (struct Tst_Question *Question); +static void Tst_FreeMediaOfQuestion (struct Tst_Question *Question); static void Tst_GetQstDataFromDB (long QstCod, + struct Tst_Question *Question, char Stem[Cns_MAX_BYTES_TEXT + 1], char Feedback[Cns_MAX_BYTES_TEXT + 1]); static long Tst_GetMedCodFromDB (long CrsCod,long QstCod,int NumOpt); @@ -241,8 +243,10 @@ static void Tst_GetMediaFromDB (long CrsCod,long QstCod,int NumOpt, struct Media *Media); static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr); -static long Tst_GetQstFromForm (char *Stem,char *Feedback); -static void Tst_MoveMediaToDefinitiveDirectories (long QstCod); +static long Tst_GetQstFromForm (struct Tst_Question *Question, + char *Stem,char *Feedback); +static void Tst_MoveMediaToDefinitiveDirectories (long QstCod, + struct Tst_Question *Question); static long Tst_GetTagCodFromTagTxt (const char *TagTxt); static long Tst_CreateNewTag (long CrsCod,const char *TagTxt); @@ -256,7 +260,8 @@ static void Tst_RemoveOneQstFromDB (long CrsCod,long QstCod); static long Tst_GetQstCod (void); -static long Tst_InsertOrUpdateQstIntoDB (long QstCod); +static long Tst_InsertOrUpdateQstIntoDB (long QstCod, + const struct Tst_Question *Question); static void Tst_InsertTagsIntoDB (long QstCod); static void Tst_InsertAnswersIntoDB (long QstCod); @@ -840,7 +845,9 @@ static void Tst_ShowOneTestQuestionWhenSeeing (unsigned NumQst,long QstCod) Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_TO_ANSWER, &Gbl.Usrs.Me.UsrDat, - NumQst,QstCod,row, + NumQst, + QstCod, + row, TsV_MAX_VISIBILITY, // All visible here &ScoreThisQst, // Not used here &AnswerIsNotBlank); // Not used here @@ -921,7 +928,9 @@ static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank /***** Write question and answers *****/ Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_RESULT, &Gbl.Usrs.Me.UsrDat, - NumQst,Gbl.Test.QstCodes[NumQst],row, + NumQst, + Gbl.Test.QstCodes[NumQst], + row, Gbl.Test.Config.Visibility, &ScoreThisQst,&AnswerIsNotBlank); @@ -966,11 +975,14 @@ static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, struct UsrData *UsrDat, - unsigned NumQst,long QstCod,MYSQL_ROW row, + unsigned NumQst, + long QstCod, + MYSQL_ROW row, unsigned Visibility, double *ScoreThisQst,bool *AnswerIsNotBlank) { extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES]; + struct Tst_Question Question; bool IsVisibleQstAndAnsTxt = TsV_IsVisibleQstAndAnsTxt (Visibility); /* row[0] UNIX_TIMESTAMP(EditTime) @@ -985,7 +997,7 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio */ /***** Create test question *****/ - Tst_QstConstructor (); + Tst_QstConstructor (&Question); HTM_TR_Begin (NULL); HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); @@ -1010,9 +1022,9 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio /***** Get and show media (row[5]) *****/ if (IsVisibleQstAndAnsTxt) { - Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); - Med_GetMediaDataByCod (&Gbl.Test.Question.Media); - Med_ShowMedia (&Gbl.Test.Question.Media, + Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); + Med_GetMediaDataByCod (&Question.Media); + Med_ShowMedia (&Question.Media, "TEST_MED_SHOW_CONT", "TEST_MED_SHOW"); } @@ -1039,7 +1051,7 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio HTM_TR_End (); /***** Destroy test question *****/ - Tst_QstDestructor (); + Tst_QstDestructor (&Question); } /*****************************************************************************/ @@ -1084,7 +1096,7 @@ void Tst_WriteQstStem (const char *Stem,const char *ClassStem,bool Visible) /************* Put form to upload a new image for a test question ************/ /*****************************************************************************/ -static void Tst_PutFormToEditQstMedia (struct Media *Media,int NumMediaInForm, +static void Tst_PutFormToEditQstMedia (const struct Media *Media,int NumMediaInForm, bool OptionsDisabled) { extern const char *The_ClassFormInBox[The_NUM_THEMES]; @@ -2857,6 +2869,7 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows, extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES]; MYSQL_RES *mysql_res; MYSQL_ROW row; + struct Tst_Question Question; static unsigned UniqueId = 0; char *Id; time_t TimeUTC; @@ -2882,7 +2895,7 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows, */ /***** Create test question *****/ - Tst_QstConstructor (); + Tst_QstConstructor (&Question); /***** Begin table row *****/ HTM_TR_Begin (NULL); @@ -2969,9 +2982,9 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows, true); // Visible /***** Get and show media (row[5]) *****/ - Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); - Med_GetMediaDataByCod (&Gbl.Test.Question.Media); - Med_ShowMedia (&Gbl.Test.Question.Media, + Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); + Med_GetMediaDataByCod (&Question.Media); + Med_ShowMedia (&Question.Media, "TEST_MED_EDIT_LIST_CONT", "TEST_MED_EDIT_LIST"); @@ -3028,7 +3041,7 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows, HTM_TR_End (); /***** Destroy test question *****/ - Tst_QstDestructor (); + Tst_QstDestructor (&Question); } /***** Free structure that stores the query result *****/ @@ -3119,6 +3132,7 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod) extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES]; MYSQL_RES *mysql_res; MYSQL_ROW row; + struct Tst_Question Question; static unsigned UniqueId = 0; char *Id; time_t TimeUTC; @@ -3141,7 +3155,7 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod) */ /***** Create test question *****/ - Tst_QstConstructor (); + Tst_QstConstructor (&Question); /***** Begin table row *****/ HTM_TR_Begin (NULL); @@ -3201,9 +3215,9 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod) true); // Visible /***** Get and show media (row[5]) *****/ - Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); - Med_GetMediaDataByCod (&Gbl.Test.Question.Media); - Med_ShowMedia (&Gbl.Test.Question.Media, + Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); + Med_GetMediaDataByCod (&Question.Media); + Med_ShowMedia (&Question.Media, "TEST_MED_EDIT_LIST_CONT", "TEST_MED_EDIT_LIST"); @@ -3218,7 +3232,7 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod) HTM_TR_End (); /***** Destroy test question *****/ - Tst_QstDestructor (); + Tst_QstDestructor (&Question); } } @@ -5071,21 +5085,22 @@ void Tst_FreeTagsList (void) void Tst_ShowFormEditOneQst (void) { long QstCod; + struct Tst_Question Question; char Stem[Cns_MAX_BYTES_TEXT + 1]; char Feedback[Cns_MAX_BYTES_TEXT + 1]; /***** Create test question *****/ - Tst_QstConstructor (); + Tst_QstConstructor (&Question); QstCod = Tst_GetQstCod (); Stem[0] = Feedback[0] = '\0'; if (QstCod > 0) // If question already exists in the database - Tst_GetQstDataFromDB (QstCod,Stem,Feedback); + Tst_GetQstDataFromDB (QstCod,&Question,Stem,Feedback); /***** Put form to edit question *****/ - Tst_PutFormEditOneQst (QstCod,Stem,Feedback); + Tst_PutFormEditOneQst (QstCod,&Question,Stem,Feedback); /***** Destroy test question *****/ - Tst_QstDestructor (); + Tst_QstDestructor (&Question); } /*****************************************************************************/ @@ -5098,6 +5113,7 @@ void Tst_ShowFormEditOneQst (void) // 3. From the action associated to reception of a question, on error in the parameters received from the form static void Tst_PutFormEditOneQst (long QstCod, + const struct Tst_Question *Question, char Stem[Cns_MAX_BYTES_TEXT + 1], char Feedback[Cns_MAX_BYTES_TEXT + 1]) { @@ -5260,7 +5276,7 @@ static void Tst_PutFormEditOneQst (long QstCod, HTM_Txt (Stem); HTM_TEXTAREA_End (); HTM_BR (); - Tst_PutFormToEditQstMedia (&Gbl.Test.Question.Media,-1, + Tst_PutFormToEditQstMedia (&Question->Media,-1, false); /***** Feedback *****/ @@ -5354,8 +5370,8 @@ static void Tst_PutFormEditOneQst (long QstCod, HTM_LABEL_Begin ("class=\"%s\"",The_ClassFormInBox[Gbl.Prefs.Theme]); HTM_INPUT_CHECKBOX ("Shuffle",HTM_DONT_SUBMIT_ON_CHANGE, "value=\"Y\"%s%s", - Gbl.Test.Question.Shuffle ? " checked=\"checked\"" : - "", + Question->Shuffle ? " checked=\"checked\"" : + "", Gbl.Test.AnswerType != Tst_ANS_UNIQUE_CHOICE && Gbl.Test.AnswerType != Tst_ANS_MULTIPLE_CHOICE ? " disabled=\"disabled\"" : ""); @@ -5547,21 +5563,22 @@ static void Tst_PutTFInputField (const char *Label,char Value) /********************* Initialize a new question to zero *********************/ /*****************************************************************************/ -void Tst_QstConstructor (void) +void Tst_QstConstructor (struct Tst_Question *Question) { unsigned NumOpt; - Gbl.Test.Question.Stem.Text = NULL; - Gbl.Test.Question.Stem.Length = 0; - Gbl.Test.Question.Feedback.Text = NULL; - Gbl.Test.Question.Feedback.Length = 0; - Gbl.Test.Question.Shuffle = false; + Question->Stem.Text = NULL; + Question->Stem.Length = 0; + Question->Feedback.Text = NULL; + Question->Feedback.Length = 0; + Question->Shuffle = false; + Gbl.Test.AnswerType = Tst_ANS_UNIQUE_CHOICE; Gbl.Test.Answer.NumOptions = 0; Gbl.Test.Answer.TF = ' '; /***** Initialize image attached to stem *****/ - Med_MediaConstructor (&Gbl.Test.Question.Media); + Med_MediaConstructor (&Question->Media); for (NumOpt = 0; NumOpt < Tst_MAX_OPTIONS_PER_QUESTION; @@ -5583,10 +5600,10 @@ void Tst_QstConstructor (void) /***************** Free memory allocated for test question *******************/ /*****************************************************************************/ -void Tst_QstDestructor (void) +void Tst_QstDestructor (struct Tst_Question *Question) { Tst_FreeTextChoiceAnswers (); - Tst_FreeMediaOfQuestion (); + Tst_FreeMediaOfQuestion (Question); } /*****************************************************************************/ @@ -5653,12 +5670,12 @@ static void Tst_FreeTextChoiceAnswer (unsigned NumOpt) /***************** Initialize images of a question to zero *******************/ /*****************************************************************************/ -static void Tst_ResetMediaOfQuestion (void) +static void Tst_ResetMediaOfQuestion (struct Tst_Question *Question) { unsigned NumOpt; /***** Reset media for stem *****/ - Med_ResetMedia (&Gbl.Test.Question.Media); + Med_ResetMedia (&Question->Media); /***** Reset media for every answer option *****/ for (NumOpt = 0; @@ -5671,11 +5688,11 @@ static void Tst_ResetMediaOfQuestion (void) /*********************** Free images of a question ***************************/ /*****************************************************************************/ -static void Tst_FreeMediaOfQuestion (void) +static void Tst_FreeMediaOfQuestion (struct Tst_Question *Question) { unsigned NumOpt; - Med_MediaDestructor (&Gbl.Test.Question.Media); + Med_MediaDestructor (&Question->Media); for (NumOpt = 0; NumOpt < Tst_MAX_OPTIONS_PER_QUESTION; NumOpt++) @@ -5687,6 +5704,7 @@ static void Tst_FreeMediaOfQuestion (void) /*****************************************************************************/ static void Tst_GetQstDataFromDB (long QstCod, + struct Tst_Question *Question, char Stem[Cns_MAX_BYTES_TEXT + 1], char Feedback[Cns_MAX_BYTES_TEXT + 1]) { @@ -5713,7 +5731,7 @@ static void Tst_GetQstDataFromDB (long QstCod, Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]); /* Get shuffle (row[1]) */ - Gbl.Test.Question.Shuffle = (row[1][0] == 'Y'); + Question->Shuffle = (row[1][0] == 'Y'); /* Get the stem of the question from the database (row[2]) */ Str_Copy (Stem,row[2], @@ -5727,8 +5745,8 @@ static void Tst_GetQstDataFromDB (long QstCod, Cns_MAX_BYTES_TEXT); /* Get media (row[4]) */ - Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[4]); - Med_GetMediaDataByCod (&Gbl.Test.Question.Media); + Question->Media.MedCod = Str_ConvertStrCodToLongCod (row[4]); + Med_GetMediaDataByCod (&Question->Media); /* Free structure that stores the query result */ DB_FreeMySQLResult (&mysql_res); @@ -5916,24 +5934,25 @@ static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *Unsigned void Tst_ReceiveQst (void) { long QstCod; + struct Tst_Question Question; char Stem[Cns_MAX_BYTES_TEXT + 1]; char Feedback[Cns_MAX_BYTES_TEXT + 1]; /***** Create test question *****/ - Tst_QstConstructor (); + Tst_QstConstructor (&Question); /***** Get parameters of the question from form *****/ Stem[0] = Feedback[0] = '\0'; - QstCod = Tst_GetQstFromForm (Stem,Feedback); + QstCod = Tst_GetQstFromForm (&Question,Stem,Feedback); /***** Make sure that tags, text and answer are not empty *****/ - if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions ()) + if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question)) { /***** Move images to definitive directories *****/ - Tst_MoveMediaToDefinitiveDirectories (QstCod); + Tst_MoveMediaToDefinitiveDirectories (QstCod,&Question); /***** Insert or update question, tags and answer in the database *****/ - QstCod = Tst_InsertOrUpdateQstTagsAnsIntoDB (QstCod); + QstCod = Tst_InsertOrUpdateQstTagsAnsIntoDB (QstCod,&Question); /***** Show the question just inserted in the database *****/ Tst_ListOneQstToEdit (QstCod); @@ -5941,21 +5960,22 @@ void Tst_ReceiveQst (void) else // Question is wrong { /***** Whether images has been received or not, reset images *****/ - Tst_ResetMediaOfQuestion (); + Tst_ResetMediaOfQuestion (&Question); /***** Put form to edit question again *****/ - Tst_PutFormEditOneQst (QstCod,Stem,Feedback); + Tst_PutFormEditOneQst (QstCod,&Question,Stem,Feedback); } /***** Destroy test question *****/ - Tst_QstDestructor (); + Tst_QstDestructor (&Question); } /*****************************************************************************/ /**************** Get parameters of a test question from form ****************/ /*****************************************************************************/ -static long Tst_GetQstFromForm (char *Stem,char *Feedback) +static long Tst_GetQstFromForm (struct Tst_Question *Question, + char *Stem,char *Feedback) { long QstCod; unsigned NumTag; @@ -6015,18 +6035,18 @@ static long Tst_GetQstFromForm (char *Stem,char *Feedback) Par_GetParToHTML ("Feedback",Feedback,Cns_MAX_BYTES_TEXT); /***** Get media associated to the stem (action, file and title) *****/ - Gbl.Test.Question.Media.Width = Tst_IMAGE_SAVED_MAX_WIDTH; - Gbl.Test.Question.Media.Height = Tst_IMAGE_SAVED_MAX_HEIGHT; - Gbl.Test.Question.Media.Quality = Tst_IMAGE_SAVED_QUALITY; + Question->Media.Width = Tst_IMAGE_SAVED_MAX_WIDTH; + Question->Media.Height = Tst_IMAGE_SAVED_MAX_HEIGHT; + Question->Media.Quality = Tst_IMAGE_SAVED_QUALITY; Med_GetMediaFromForm (Gbl.Hierarchy.Crs.CrsCod,QstCod, -1, // < 0 ==> the image associated to the stem - &Gbl.Test.Question.Media, + &Question->Media, Tst_GetMediaFromDB, NULL); Ale_ShowAlerts (NULL); /***** Get answers *****/ - Gbl.Test.Question.Shuffle = false; + Question->Shuffle = false; switch (Gbl.Test.AnswerType) { case Tst_ANS_INT: @@ -6059,7 +6079,7 @@ static long Tst_GetQstFromForm (char *Stem,char *Feedback) case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE: /* Get shuffle */ - Gbl.Test.Question.Shuffle = Par_GetParToBool ("Shuffle"); + Question->Shuffle = Par_GetParToBool ("Shuffle"); /* falls through */ /* no break */ case Tst_ANS_TEXT: @@ -6146,10 +6166,10 @@ static long Tst_GetQstFromForm (char *Stem,char *Feedback) NumTag++) if (Gbl.Test.Tags.Txt[NumTag][0]) Gbl.Test.Tags.Num++; - Gbl.Test.Question.Stem.Text = Stem; - Gbl.Test.Question.Stem.Length = strlen (Gbl.Test.Question.Stem.Text); - Gbl.Test.Question.Feedback.Text = Feedback; - Gbl.Test.Question.Feedback.Length = strlen (Gbl.Test.Question.Feedback.Text); + Question->Stem.Text = Stem; + Question->Stem.Length = strlen (Question->Stem.Text); + Question->Feedback.Text = Feedback; + Question->Feedback.Length = strlen (Question->Feedback.Text); return QstCod; } @@ -6161,7 +6181,7 @@ static long Tst_GetQstFromForm (char *Stem,char *Feedback) // Counts Gbl.Test.Answer.NumOptions // Computes Gbl.Test.Answer.Integer and Gbl.Test.Answer.FloatingPoint[0..1] -bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void) +bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (const struct Tst_Question *Question) { extern const char *Txt_You_must_type_at_least_one_tag_for_the_question; extern const char *Txt_You_must_type_the_stem_of_the_question; @@ -6189,7 +6209,7 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void) } /***** A question must have a stem*****/ - if (!Gbl.Test.Question.Stem.Length) + if (!Question->Stem.Length) { Ale_ShowAlert (Ale_WARNING,Txt_You_must_type_the_stem_of_the_question); return false; @@ -6343,7 +6363,7 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void) /*********** Check if a test question already exists in database *************/ /*****************************************************************************/ -bool Tst_CheckIfQuestionExistsInDB (void) +bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question) { extern const char *Tst_StrAnswerTypesDB[Tst_NUM_ANS_TYPES]; MYSQL_RES *mysql_res_qst; @@ -6366,7 +6386,7 @@ bool Tst_CheckIfQuestionExistsInDB (void) " WHERE CrsCod=%ld AND AnsType='%s' AND Stem='%s'", Gbl.Hierarchy.Crs.CrsCod, Tst_StrAnswerTypesDB[Gbl.Test.AnswerType], - Gbl.Test.Question.Stem.Text); + Question->Stem.Text); if (NumQstsWithThisStem) // There are questions in database with the same stem that the one of this question { @@ -6449,7 +6469,8 @@ bool Tst_CheckIfQuestionExistsInDB (void) /* Move images associates to a test question to their definitive directories */ /*****************************************************************************/ -static void Tst_MoveMediaToDefinitiveDirectories (long QstCod) +static void Tst_MoveMediaToDefinitiveDirectories (long QstCod, + struct Tst_Question *Question) { unsigned NumOpt; long CurrentMedCodInDB; @@ -6457,7 +6478,7 @@ static void Tst_MoveMediaToDefinitiveDirectories (long QstCod) /***** Media associated to question stem *****/ CurrentMedCodInDB = Tst_GetMedCodFromDB (Gbl.Hierarchy.Crs.CrsCod,QstCod, -1L); // Get current media code associated to stem - Med_RemoveKeepOrStoreMedia (CurrentMedCodInDB,&Gbl.Test.Question.Media); + Med_RemoveKeepOrStoreMedia (CurrentMedCodInDB,&Question->Media); /****** Move media associated to answers *****/ if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE || @@ -6859,10 +6880,11 @@ void Tst_PutParamQstCod (long QstCod) /******** Insert or update question, tags and anser in the database **********/ /*****************************************************************************/ -long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod) +long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod, + const struct Tst_Question *Question) { /***** Insert or update question in the table of questions *****/ - QstCod = Tst_InsertOrUpdateQstIntoDB (QstCod); + QstCod = Tst_InsertOrUpdateQstIntoDB (QstCod,Question); if (QstCod > 0) { /***** Insert tags in the tags table *****/ @@ -6882,7 +6904,8 @@ long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod) /*********** Insert or update question in the table of questions *************/ /*****************************************************************************/ -static long Tst_InsertOrUpdateQstIntoDB (long QstCod) +static long Tst_InsertOrUpdateQstIntoDB (long QstCod, + const struct Tst_Question *Question) { if (QstCod < 0) // It's a new question { @@ -6890,21 +6913,33 @@ static long Tst_InsertOrUpdateQstIntoDB (long QstCod) QstCod = DB_QueryINSERTandReturnCode ("can not create question", "INSERT INTO tst_questions" - " (CrsCod,EditTime,AnsType,Shuffle," - "Stem,Feedback,MedCod," - "NumHits,Score)" + " (CrsCod," + "EditTime," + "AnsType," + "Shuffle," + "Stem," + "Feedback," + "MedCod," + "NumHits," + "Score)" " VALUES" - " (%ld,NOW(),'%s','%c'," - "'%s','%s',%ld," - "0,0)", + " (%ld," // CrsCod + "NOW()," // EditTime + "'%s'," // AnsType + "'%c'," // Shuffle + "'%s'," // Stem + "'%s'," // Feedback + "%ld," // MedCod + "0," // NumHits + "0)", // Score Gbl.Hierarchy.Crs.CrsCod, Tst_StrAnswerTypesDB[Gbl.Test.AnswerType], - Gbl.Test.Question.Shuffle ? 'Y' : - 'N', - Gbl.Test.Question.Stem.Text, - Gbl.Test.Question.Feedback.Text ? Gbl.Test.Question.Feedback.Text : - "", - Gbl.Test.Question.Media.MedCod); + Question->Shuffle ? 'Y' : + 'N', + Question->Stem.Text, + Question->Feedback.Text ? Question->Feedback.Text : + "", + Question->Media.MedCod); } else // It's an existing question { @@ -6912,16 +6947,20 @@ static long Tst_InsertOrUpdateQstIntoDB (long QstCod) /* Update question in database */ DB_QueryUPDATE ("can not update question", "UPDATE tst_questions" - " SET EditTime=NOW(),AnsType='%s',Shuffle='%c'," - "Stem='%s',Feedback='%s',MedCod=%ld" + " SET EditTime=NOW()," + "AnsType='%s'," + "Shuffle='%c'," + "Stem='%s'," + "Feedback='%s'," + "MedCod=%ld" " WHERE QstCod=%ld AND CrsCod=%ld", Tst_StrAnswerTypesDB[Gbl.Test.AnswerType], - Gbl.Test.Question.Shuffle ? 'Y' : - 'N', - Gbl.Test.Question.Stem.Text, - Gbl.Test.Question.Feedback.Text ? Gbl.Test.Question.Feedback.Text : - "", - Gbl.Test.Question.Media.MedCod, + Question->Shuffle ? 'Y' : + 'N', + Question->Stem.Text, + Question->Feedback.Text ? Question->Feedback.Text : + "", + Question->Media.MedCod, QstCod,Gbl.Hierarchy.Crs.CrsCod); /* Remove answers and tags from this test question */ diff --git a/swad_test.h b/swad_test.h index 82ac3ee13..a04ea1e89 100644 --- a/swad_test.h +++ b/swad_test.h @@ -147,7 +147,9 @@ void Tst_ShowTagList (unsigned NumTags,MYSQL_RES *mysql_res); void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, struct UsrData *UsrDat, - unsigned NumQst,long QstCod,MYSQL_ROW row, + unsigned NumQst, + long QstCod, + MYSQL_ROW row, unsigned Visibility, double *ScoreThisQst,bool *AnswerIsNotBlank); void Tst_WriteQstStem (const char *Stem,const char *ClassStem,bool Visible); @@ -193,16 +195,16 @@ bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void); void Tst_ReceiveConfigTst (void); void Tst_ShowFormEditOneQst (void); -void Tst_QstConstructor (void); -void Tst_QstDestructor (void); +void Tst_QstConstructor (struct Tst_Question *Question); +void Tst_QstDestructor (struct Tst_Question *Question); int Tst_AllocateTextChoiceAnswer (unsigned NumOpt); Tst_AnswerType_t Tst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD); void Tst_ReceiveQst (void); -bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void); +bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (const struct Tst_Question *Question); -bool Tst_CheckIfQuestionExistsInDB (void); +bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question); long Tst_GetIntAnsFromStr (char *Str); @@ -218,7 +220,8 @@ long Tst_GetParamGblQstCod (void); void Tst_PutParamGblQstCod (void); void Tst_PutParamQstCod (long QstCod); -long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod); +long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod, + const struct Tst_Question *Question); void Tst_RemoveCrsTests (long CrsCod); diff --git a/swad_test_import.c b/swad_test_import.c index 991c0afc6..b521b8bed 100644 --- a/swad_test_import.c +++ b/swad_test_import.c @@ -79,6 +79,7 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem); static void TsI_WriteHeadingListImportedQst (void); static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, struct XMLElement *FeedbackElem, + const struct Tst_Question *Question, bool QuestionExists); /*****************************************************************************/ @@ -528,6 +529,7 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer) struct XMLAttribute *Attribute; bool AnswerTypeFound; bool QuestionExists; + struct Tst_Question Question; char Stem[Cns_MAX_BYTES_TEXT + 1]; char Feedback[Cns_MAX_BYTES_TEXT + 1]; @@ -571,7 +573,7 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer) if (!strcmp (QuestionElem->TagName,"question")) { /***** Create test question *****/ - Tst_QstConstructor (); + Tst_QstConstructor (&Question); /* Get type of questions (in mandatory attribute "type") */ AnswerTypeFound = false; @@ -623,8 +625,8 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer) Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML, Stem,Cns_MAX_BYTES_TEXT,true); - Gbl.Test.Question.Stem.Text = Stem; - Gbl.Test.Question.Stem.Length = strlen (Stem); + Question.Stem.Text = Stem; + Question.Stem.Length = strlen (Stem); } break; // Only first element "stem" } @@ -643,14 +645,14 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer) Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML, Feedback,Cns_MAX_BYTES_TEXT,true); - Gbl.Test.Question.Feedback.Text = Feedback; - Gbl.Test.Question.Feedback.Length = strlen (Feedback); + Question.Feedback.Text = Feedback; + Question.Feedback.Length = strlen (Feedback); } break; // Only first element "feedback" } /* Get shuffle. By default, shuffle is false. */ - Gbl.Test.Question.Shuffle = false; + Question.Shuffle = false; for (AnswerElem = QuestionElem->FirstChild; AnswerElem != NULL; AnswerElem = AnswerElem->NextBrother) @@ -664,7 +666,7 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer) Attribute = Attribute->Next) if (!strcmp (Attribute->AttributeName,"shuffle")) { - Gbl.Test.Question.Shuffle = XML_GetAttributteYesNoFromXMLTree (Attribute); + Question.Shuffle = XML_GetAttributteYesNoFromXMLTree (Attribute); break; // Only first attribute "shuffle" } break; // Only first element "answer" @@ -674,22 +676,22 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer) TsI_GetAnswerFromXML (AnswerElem); /* Make sure that tags, text and answer are not empty */ - if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions ()) + if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question)) { /* Check if question already exists in database */ - QuestionExists = Tst_CheckIfQuestionExistsInDB (); + QuestionExists = Tst_CheckIfQuestionExistsInDB (&Question); /* Write row with this imported question */ - TsI_WriteRowImportedQst (StemElem,FeedbackElem,QuestionExists); + TsI_WriteRowImportedQst (StemElem,FeedbackElem,&Question,QuestionExists); /***** If a new question ==> insert question, tags and answer in the database *****/ if (!QuestionExists) - if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L) <= 0) + if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L,&Question) <= 0) Lay_ShowErrorAndExit ("Can not create question."); } /***** Destroy test question *****/ - Tst_QstDestructor (); + Tst_QstDestructor (&Question); } } @@ -899,6 +901,7 @@ static void TsI_WriteHeadingListImportedQst (void) static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, struct XMLElement *FeedbackElem, + const struct Tst_Question *Question, bool QuestionExists) { extern const char *Txt_Existing_question; @@ -986,7 +989,7 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem, if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE || Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE) /* Put an icon that indicates whether shuffle is enabled or not */ - if (Gbl.Test.Question.Shuffle) + if (Question->Shuffle) Ico_PutIcon ("check.svg",Txt_TST_Answer_given_by_the_teachers, QuestionExists ? "ICO_HIDDEN ICO16x16" : "ICO16x16"); diff --git a/swad_test_result.c b/swad_test_result.c index 28a788c16..6d2a3e684 100644 --- a/swad_test_result.c +++ b/swad_test_result.c @@ -901,7 +901,8 @@ void TsR_ShowTestResult (struct UsrData *UsrDat, /***** Write questions and answers *****/ Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_RESULT, UsrDat, - NumQst,Gbl.Test.QstCodes[NumQst],row, + NumQst,Gbl.Test.QstCodes[NumQst], + row, Visibility, &ScoreThisQst, // Not used here &AnswerIsNotBlank); // Not used here