Version19.148.3

This commit is contained in:
acanas 2020-03-17 14:47:58 +01:00
parent 3810f664c2
commit 11d934a3cc
10 changed files with 186 additions and 137 deletions

View File

@ -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.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.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.1: Mar 17, 2020 Code refactoring in tests. (282851 lines)
Version 19.148: Mar 17, 2020 Code refactoring in tests. Version 19.148: Mar 17, 2020 Code refactoring in tests.

View File

@ -1874,6 +1874,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
unsigned NumQst; unsigned NumQst;
MYSQL_ROW row; MYSQL_ROW row;
long QstCod; long QstCod;
struct Tst_Question Question;
unsigned QstInd; unsigned QstInd;
unsigned MaxQstInd; unsigned MaxQstInd;
char StrQstInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; char StrQstInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
@ -1907,7 +1908,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
row[1] QstCod row[1] QstCod
*/ */
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (); Tst_QstConstructor (&Question);
/* Get question index (row[0]) */ /* Get question index (row[0]) */
QstInd = Str_ConvertStrToUnsigned (row[0]); QstInd = Str_ConvertStrToUnsigned (row[0]);
@ -1976,7 +1977,7 @@ static void Gam_ListOneOrMoreQuestionsForEdition (long GamCod,unsigned NumQsts,
HTM_TR_End (); HTM_TR_End ();
/***** Destroy test question *****/ /***** Destroy test question *****/
Tst_QstDestructor (); Tst_QstDestructor (&Question);
} }
/***** End table *****/ /***** End table *****/
@ -1994,6 +1995,7 @@ static void Gam_ListQuestionForEdition (long QstCod,const char *StrQstInd)
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
bool QstExists; bool QstExists;
struct Media Media;
/***** Get question from database *****/ /***** Get question from database *****/
QstExists = Tst_GetOneQuestionByCod (QstCod,&mysql_res); // Question exists? QstExists = Tst_GetOneQuestionByCod (QstCod,&mysql_res); // Question exists?
@ -2054,11 +2056,11 @@ static void Gam_ListQuestionForEdition (long QstCod,const char *StrQstInd)
true); // Visible true); // Visible
/* Get media (row[5]) */ /* Get media (row[5]) */
Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); Media.MedCod = Str_ConvertStrCodToLongCod (row[5]);
Med_GetMediaDataByCod (&Gbl.Test.Question.Media); Med_GetMediaDataByCod (&Media);
/* Show media */ /* Show media */
Med_ShowMedia (&Gbl.Test.Question.Media, Med_ShowMedia (&Media,
"TEST_MED_EDIT_LIST_STEM_CONTAINER", "TEST_MED_EDIT_LIST_STEM_CONTAINER",
"TEST_MED_EDIT_LIST_STEM"); "TEST_MED_EDIT_LIST_STEM");

View File

@ -666,7 +666,6 @@ struct Globals
char StrAnswersOneQst[Tst_MAX_QUESTIONS_PER_TEST][Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user 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 AllowTeachers; // Can teachers of this course see the test result?
bool AllAnsTypes; bool AllAnsTypes;
struct Tst_Question Question;
struct struct
{ {
unsigned NumOptions; unsigned NumOptions;

View File

@ -2863,6 +2863,7 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match)
extern const char *Txt_Question_removed; extern const char *Txt_Question_removed;
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
struct Media Media;
/***** Trivial check: do not show anything on match start and end *****/ /***** Trivial check: do not show anything on match start and end *****/
switch (Match->Status.Showing) switch (Match->Status.Showing)
@ -2899,11 +2900,11 @@ static void Mch_ShowQuestionAndAnswersTch (const struct Match *Match)
true); // Visible true); // Visible
/* Get media (row[2]) */ /* Get media (row[2]) */
Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[2]); Media.MedCod = Str_ConvertStrCodToLongCod (row[2]);
Med_GetMediaDataByCod (&Gbl.Test.Question.Media); Med_GetMediaDataByCod (&Media);
/* Show media */ /* Show media */
Med_ShowMedia (&Gbl.Test.Question.Media, Med_ShowMedia (&Media,
"TEST_MED_EDIT_LIST_STEM_CONTAINER", "TEST_MED_EDIT_LIST_STEM_CONTAINER",
"TEST_MED_EDIT_LIST_STEM"); "TEST_MED_EDIT_LIST_STEM");

View File

@ -161,17 +161,17 @@ static bool Med_MoveTmpFileToDefDir (struct Media *Media,
const char PathMedPriv[PATH_MAX + 1], const char PathMedPriv[PATH_MAX + 1],
const char *Extension); 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 PathMedPriv[PATH_MAX + 1],
const char *ClassMedia); 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 PathMedPriv[PATH_MAX + 1],
const char *ClassMedia); 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 PathMedPriv[PATH_MAX + 1],
const char *ClassMedia); const char *ClassMedia);
static void Med_ShowYoutube (struct Media *Media,const char *ClassMedia); static void Med_ShowYoutube (const struct Media *Media,const char *ClassMedia);
static void Med_ShowEmbed (struct Media *Media,const char *ClassMedia); static void Med_ShowEmbed (const struct Media *Media,const char *ClassMedia);
static void Med_AlertThirdPartyCookies (void); static void Med_AlertThirdPartyCookies (void);
static Med_Type_t Med_GetTypeFromStrInDB (const char *Str); 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.) ******/ /****** 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) const char *ClassContainer,const char *ClassMedia)
{ {
bool PutLink; bool PutLink;
@ -1515,7 +1515,7 @@ void Med_ShowMedia (struct Media *Media,
/************************** Show a user uploaded JPG *************************/ /************************** 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 PathMedPriv[PATH_MAX + 1],
const char *ClassMedia) const char *ClassMedia)
{ {
@ -1559,7 +1559,7 @@ static void Med_ShowJPG (struct Media *Media,
/************************** Show a user uploaded GIF *************************/ /************************** 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 PathMedPriv[PATH_MAX + 1],
const char *ClassMedia) const char *ClassMedia)
{ {
@ -1650,7 +1650,7 @@ static void Med_ShowGIF (struct Media *Media,
/************************ Show a user uploaded video *************************/ /************************ 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 PathMedPriv[PATH_MAX + 1],
const char *ClassMedia) const char *ClassMedia)
{ {
@ -1704,7 +1704,7 @@ static void Med_ShowVideo (struct Media *Media,
/*********************** Show an embed YouTube video *************************/ /*********************** 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 *****/ /***** Check if YouTube code exists *****/
if (Media->Name[0]) // YouTube code if (Media->Name[0]) // YouTube code
@ -1744,7 +1744,7 @@ static void Med_ShowYoutube (struct Media *Media,const char *ClassMedia)
/*************************** Show an embed media *****************************/ /*************************** 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 *****/ /***** Check if embed URL exists *****/
if (Media->URL[0]) // Embed URL if (Media->URL[0]) // Embed URL

View File

@ -150,7 +150,7 @@ void Med_RemoveKeepOrStoreMedia (long CurrentMedCodInDB,struct Media *Media);
void Med_MoveMediaToDefinitiveDir (struct Media *Media); void Med_MoveMediaToDefinitiveDir (struct Media *Media);
void Med_StoreMediaInDB (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); const char *ClassContainer,const char *ClassMedia);
void Med_RemoveMediaFromAllRows (unsigned NumMedia,MYSQL_RES *mysql_res); void Med_RemoveMediaFromAllRows (unsigned NumMedia,MYSQL_RES *mysql_res);

View File

@ -138,7 +138,7 @@ static unsigned Tst_GetNumAccessesTst (void);
static void Tst_ShowTestQuestionsWhenSeeing (MYSQL_RES *mysql_res); static void Tst_ShowTestQuestionsWhenSeeing (MYSQL_RES *mysql_res);
static void Tst_ShowOneTestQuestionWhenSeeing (unsigned NumQst,long QstCod); static void Tst_ShowOneTestQuestionWhenSeeing (unsigned NumQst,long QstCod);
static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank,double *TotalScore); 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); bool OptionsDisabled);
static void Tst_UpdateScoreQst (long QstCod,double ScoreThisQst,bool AnswerIsNotBlank); static void Tst_UpdateScoreQst (long QstCod,double ScoreThisQst,bool AnswerIsNotBlank);
static void Tst_UpdateMyNumAccessTst (unsigned NumAccessesTst); static void Tst_UpdateMyNumAccessTst (unsigned NumAccessesTst);
@ -221,6 +221,7 @@ static void Tst_GetParamNumQst (void);
static int Tst_CountNumTagsInList (void); static int Tst_CountNumTagsInList (void);
static int Tst_CountNumAnswerTypesInList (void); static int Tst_CountNumAnswerTypesInList (void);
static void Tst_PutFormEditOneQst (long QstCod, static void Tst_PutFormEditOneQst (long QstCod,
const struct Tst_Question *Question,
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]);
static void Tst_PutFloatInputField (const char *Label,const char *Field, 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_FreeTextChoiceAnswers (void);
static void Tst_FreeTextChoiceAnswer (unsigned NumOpt); static void Tst_FreeTextChoiceAnswer (unsigned NumOpt);
static void Tst_ResetMediaOfQuestion (void); static void Tst_ResetMediaOfQuestion (struct Tst_Question *Question);
static void Tst_FreeMediaOfQuestion (void); static void Tst_FreeMediaOfQuestion (struct Tst_Question *Question);
static void Tst_GetQstDataFromDB (long QstCod, static void Tst_GetQstDataFromDB (long QstCod,
struct Tst_Question *Question,
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]);
static long Tst_GetMedCodFromDB (long CrsCod,long QstCod,int NumOpt); 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); struct Media *Media);
static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr); static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr);
static long Tst_GetQstFromForm (char *Stem,char *Feedback); static long Tst_GetQstFromForm (struct Tst_Question *Question,
static void Tst_MoveMediaToDefinitiveDirectories (long QstCod); char *Stem,char *Feedback);
static void Tst_MoveMediaToDefinitiveDirectories (long QstCod,
struct Tst_Question *Question);
static long Tst_GetTagCodFromTagTxt (const char *TagTxt); static long Tst_GetTagCodFromTagTxt (const char *TagTxt);
static long Tst_CreateNewTag (long CrsCod,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_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_InsertTagsIntoDB (long QstCod);
static void Tst_InsertAnswersIntoDB (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, Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_TO_ANSWER,
&Gbl.Usrs.Me.UsrDat, &Gbl.Usrs.Me.UsrDat,
NumQst,QstCod,row, NumQst,
QstCod,
row,
TsV_MAX_VISIBILITY, // All visible here TsV_MAX_VISIBILITY, // All visible here
&ScoreThisQst, // Not used here &ScoreThisQst, // Not used here
&AnswerIsNotBlank); // Not used here &AnswerIsNotBlank); // Not used here
@ -921,7 +928,9 @@ static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank
/***** Write question and answers *****/ /***** Write question and answers *****/
Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_RESULT, Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_RESULT,
&Gbl.Usrs.Me.UsrDat, &Gbl.Usrs.Me.UsrDat,
NumQst,Gbl.Test.QstCodes[NumQst],row, NumQst,
Gbl.Test.QstCodes[NumQst],
row,
Gbl.Test.Config.Visibility, Gbl.Test.Config.Visibility,
&ScoreThisQst,&AnswerIsNotBlank); &ScoreThisQst,&AnswerIsNotBlank);
@ -966,11 +975,14 @@ static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank
void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions,
struct UsrData *UsrDat, struct UsrData *UsrDat,
unsigned NumQst,long QstCod,MYSQL_ROW row, unsigned NumQst,
long QstCod,
MYSQL_ROW row,
unsigned Visibility, unsigned Visibility,
double *ScoreThisQst,bool *AnswerIsNotBlank) double *ScoreThisQst,bool *AnswerIsNotBlank)
{ {
extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES]; extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES];
struct Tst_Question Question;
bool IsVisibleQstAndAnsTxt = TsV_IsVisibleQstAndAnsTxt (Visibility); bool IsVisibleQstAndAnsTxt = TsV_IsVisibleQstAndAnsTxt (Visibility);
/* /*
row[0] UNIX_TIMESTAMP(EditTime) row[0] UNIX_TIMESTAMP(EditTime)
@ -985,7 +997,7 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio
*/ */
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (); Tst_QstConstructor (&Question);
HTM_TR_Begin (NULL); HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); 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]) *****/ /***** Get and show media (row[5]) *****/
if (IsVisibleQstAndAnsTxt) if (IsVisibleQstAndAnsTxt)
{ {
Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]);
Med_GetMediaDataByCod (&Gbl.Test.Question.Media); Med_GetMediaDataByCod (&Question.Media);
Med_ShowMedia (&Gbl.Test.Question.Media, Med_ShowMedia (&Question.Media,
"TEST_MED_SHOW_CONT", "TEST_MED_SHOW_CONT",
"TEST_MED_SHOW"); "TEST_MED_SHOW");
} }
@ -1039,7 +1051,7 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio
HTM_TR_End (); HTM_TR_End ();
/***** Destroy test question *****/ /***** 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 ************/ /************* 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) bool OptionsDisabled)
{ {
extern const char *The_ClassFormInBox[The_NUM_THEMES]; 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]; extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES];
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
struct Tst_Question Question;
static unsigned UniqueId = 0; static unsigned UniqueId = 0;
char *Id; char *Id;
time_t TimeUTC; time_t TimeUTC;
@ -2882,7 +2895,7 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
*/ */
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (); Tst_QstConstructor (&Question);
/***** Begin table row *****/ /***** Begin table row *****/
HTM_TR_Begin (NULL); HTM_TR_Begin (NULL);
@ -2969,9 +2982,9 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
true); // Visible true); // Visible
/***** Get and show media (row[5]) *****/ /***** Get and show media (row[5]) *****/
Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]);
Med_GetMediaDataByCod (&Gbl.Test.Question.Media); Med_GetMediaDataByCod (&Question.Media);
Med_ShowMedia (&Gbl.Test.Question.Media, Med_ShowMedia (&Question.Media,
"TEST_MED_EDIT_LIST_CONT", "TEST_MED_EDIT_LIST_CONT",
"TEST_MED_EDIT_LIST"); "TEST_MED_EDIT_LIST");
@ -3028,7 +3041,7 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
HTM_TR_End (); HTM_TR_End ();
/***** Destroy test question *****/ /***** Destroy test question *****/
Tst_QstDestructor (); Tst_QstDestructor (&Question);
} }
/***** Free structure that stores the query result *****/ /***** 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]; extern const char *Txt_TST_STR_ANSWER_TYPES[Tst_NUM_ANS_TYPES];
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
struct Tst_Question Question;
static unsigned UniqueId = 0; static unsigned UniqueId = 0;
char *Id; char *Id;
time_t TimeUTC; time_t TimeUTC;
@ -3141,7 +3155,7 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod)
*/ */
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (); Tst_QstConstructor (&Question);
/***** Begin table row *****/ /***** Begin table row *****/
HTM_TR_Begin (NULL); HTM_TR_Begin (NULL);
@ -3201,9 +3215,9 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod)
true); // Visible true); // Visible
/***** Get and show media (row[5]) *****/ /***** Get and show media (row[5]) *****/
Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]); Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[5]);
Med_GetMediaDataByCod (&Gbl.Test.Question.Media); Med_GetMediaDataByCod (&Question.Media);
Med_ShowMedia (&Gbl.Test.Question.Media, Med_ShowMedia (&Question.Media,
"TEST_MED_EDIT_LIST_CONT", "TEST_MED_EDIT_LIST_CONT",
"TEST_MED_EDIT_LIST"); "TEST_MED_EDIT_LIST");
@ -3218,7 +3232,7 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod)
HTM_TR_End (); HTM_TR_End ();
/***** Destroy test question *****/ /***** Destroy test question *****/
Tst_QstDestructor (); Tst_QstDestructor (&Question);
} }
} }
@ -5071,21 +5085,22 @@ void Tst_FreeTagsList (void)
void Tst_ShowFormEditOneQst (void) void Tst_ShowFormEditOneQst (void)
{ {
long QstCod; long QstCod;
struct Tst_Question Question;
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];
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (); Tst_QstConstructor (&Question);
QstCod = Tst_GetQstCod (); QstCod = Tst_GetQstCod ();
Stem[0] = Feedback[0] = '\0'; Stem[0] = Feedback[0] = '\0';
if (QstCod > 0) // If question already exists in the database 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 *****/ /***** Put form to edit question *****/
Tst_PutFormEditOneQst (QstCod,Stem,Feedback); Tst_PutFormEditOneQst (QstCod,&Question,Stem,Feedback);
/***** Destroy test question *****/ /***** 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 // 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, static void Tst_PutFormEditOneQst (long QstCod,
const struct Tst_Question *Question,
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])
{ {
@ -5260,7 +5276,7 @@ static void Tst_PutFormEditOneQst (long QstCod,
HTM_Txt (Stem); HTM_Txt (Stem);
HTM_TEXTAREA_End (); HTM_TEXTAREA_End ();
HTM_BR (); HTM_BR ();
Tst_PutFormToEditQstMedia (&Gbl.Test.Question.Media,-1, Tst_PutFormToEditQstMedia (&Question->Media,-1,
false); false);
/***** Feedback *****/ /***** Feedback *****/
@ -5354,8 +5370,8 @@ static void Tst_PutFormEditOneQst (long QstCod,
HTM_LABEL_Begin ("class=\"%s\"",The_ClassFormInBox[Gbl.Prefs.Theme]); HTM_LABEL_Begin ("class=\"%s\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
HTM_INPUT_CHECKBOX ("Shuffle",HTM_DONT_SUBMIT_ON_CHANGE, HTM_INPUT_CHECKBOX ("Shuffle",HTM_DONT_SUBMIT_ON_CHANGE,
"value=\"Y\"%s%s", "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_UNIQUE_CHOICE &&
Gbl.Test.AnswerType != Tst_ANS_MULTIPLE_CHOICE ? " disabled=\"disabled\"" : 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 *********************/ /********************* Initialize a new question to zero *********************/
/*****************************************************************************/ /*****************************************************************************/
void Tst_QstConstructor (void) void Tst_QstConstructor (struct Tst_Question *Question)
{ {
unsigned NumOpt; unsigned NumOpt;
Gbl.Test.Question.Stem.Text = NULL; Question->Stem.Text = NULL;
Gbl.Test.Question.Stem.Length = 0; Question->Stem.Length = 0;
Gbl.Test.Question.Feedback.Text = NULL; Question->Feedback.Text = NULL;
Gbl.Test.Question.Feedback.Length = 0; Question->Feedback.Length = 0;
Gbl.Test.Question.Shuffle = false; Question->Shuffle = false;
Gbl.Test.AnswerType = Tst_ANS_UNIQUE_CHOICE; Gbl.Test.AnswerType = Tst_ANS_UNIQUE_CHOICE;
Gbl.Test.Answer.NumOptions = 0; Gbl.Test.Answer.NumOptions = 0;
Gbl.Test.Answer.TF = ' '; Gbl.Test.Answer.TF = ' ';
/***** Initialize image attached to stem *****/ /***** Initialize image attached to stem *****/
Med_MediaConstructor (&Gbl.Test.Question.Media); Med_MediaConstructor (&Question->Media);
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION; NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
@ -5583,10 +5600,10 @@ void Tst_QstConstructor (void)
/***************** Free memory allocated for test question *******************/ /***************** Free memory allocated for test question *******************/
/*****************************************************************************/ /*****************************************************************************/
void Tst_QstDestructor (void) void Tst_QstDestructor (struct Tst_Question *Question)
{ {
Tst_FreeTextChoiceAnswers (); Tst_FreeTextChoiceAnswers ();
Tst_FreeMediaOfQuestion (); Tst_FreeMediaOfQuestion (Question);
} }
/*****************************************************************************/ /*****************************************************************************/
@ -5653,12 +5670,12 @@ static void Tst_FreeTextChoiceAnswer (unsigned NumOpt)
/***************** Initialize images of a question to zero *******************/ /***************** Initialize images of a question to zero *******************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_ResetMediaOfQuestion (void) static void Tst_ResetMediaOfQuestion (struct Tst_Question *Question)
{ {
unsigned NumOpt; unsigned NumOpt;
/***** Reset media for stem *****/ /***** Reset media for stem *****/
Med_ResetMedia (&Gbl.Test.Question.Media); Med_ResetMedia (&Question->Media);
/***** Reset media for every answer option *****/ /***** Reset media for every answer option *****/
for (NumOpt = 0; for (NumOpt = 0;
@ -5671,11 +5688,11 @@ static void Tst_ResetMediaOfQuestion (void)
/*********************** Free images of a question ***************************/ /*********************** Free images of a question ***************************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_FreeMediaOfQuestion (void) static void Tst_FreeMediaOfQuestion (struct Tst_Question *Question)
{ {
unsigned NumOpt; unsigned NumOpt;
Med_MediaDestructor (&Gbl.Test.Question.Media); Med_MediaDestructor (&Question->Media);
for (NumOpt = 0; for (NumOpt = 0;
NumOpt < Tst_MAX_OPTIONS_PER_QUESTION; NumOpt < Tst_MAX_OPTIONS_PER_QUESTION;
NumOpt++) NumOpt++)
@ -5687,6 +5704,7 @@ static void Tst_FreeMediaOfQuestion (void)
/*****************************************************************************/ /*****************************************************************************/
static void Tst_GetQstDataFromDB (long QstCod, static void Tst_GetQstDataFromDB (long QstCod,
struct Tst_Question *Question,
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])
{ {
@ -5713,7 +5731,7 @@ static void Tst_GetQstDataFromDB (long QstCod,
Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]); Gbl.Test.AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[0]);
/* Get shuffle (row[1]) */ /* 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]) */ /* Get the stem of the question from the database (row[2]) */
Str_Copy (Stem,row[2], Str_Copy (Stem,row[2],
@ -5727,8 +5745,8 @@ static void Tst_GetQstDataFromDB (long QstCod,
Cns_MAX_BYTES_TEXT); Cns_MAX_BYTES_TEXT);
/* Get media (row[4]) */ /* Get media (row[4]) */
Gbl.Test.Question.Media.MedCod = Str_ConvertStrCodToLongCod (row[4]); Question->Media.MedCod = Str_ConvertStrCodToLongCod (row[4]);
Med_GetMediaDataByCod (&Gbl.Test.Question.Media); Med_GetMediaDataByCod (&Question->Media);
/* Free structure that stores the query result */ /* Free structure that stores the query result */
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
@ -5916,24 +5934,25 @@ static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *Unsigned
void Tst_ReceiveQst (void) void Tst_ReceiveQst (void)
{ {
long QstCod; long QstCod;
struct Tst_Question Question;
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];
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (); Tst_QstConstructor (&Question);
/***** Get parameters of the question from form *****/ /***** Get parameters of the question from form *****/
Stem[0] = Feedback[0] = '\0'; 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 *****/ /***** Make sure that tags, text and answer are not empty *****/
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions ()) if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question))
{ {
/***** Move images to definitive directories *****/ /***** Move images to definitive directories *****/
Tst_MoveMediaToDefinitiveDirectories (QstCod); Tst_MoveMediaToDefinitiveDirectories (QstCod,&Question);
/***** Insert or update question, tags and answer in the database *****/ /***** 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 *****/ /***** Show the question just inserted in the database *****/
Tst_ListOneQstToEdit (QstCod); Tst_ListOneQstToEdit (QstCod);
@ -5941,21 +5960,22 @@ void Tst_ReceiveQst (void)
else // Question is wrong else // Question is wrong
{ {
/***** Whether images has been received or not, reset images *****/ /***** Whether images has been received or not, reset images *****/
Tst_ResetMediaOfQuestion (); Tst_ResetMediaOfQuestion (&Question);
/***** Put form to edit question again *****/ /***** Put form to edit question again *****/
Tst_PutFormEditOneQst (QstCod,Stem,Feedback); Tst_PutFormEditOneQst (QstCod,&Question,Stem,Feedback);
} }
/***** Destroy test question *****/ /***** Destroy test question *****/
Tst_QstDestructor (); Tst_QstDestructor (&Question);
} }
/*****************************************************************************/ /*****************************************************************************/
/**************** Get parameters of a test question from form ****************/ /**************** 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; long QstCod;
unsigned NumTag; unsigned NumTag;
@ -6015,18 +6035,18 @@ static long Tst_GetQstFromForm (char *Stem,char *Feedback)
Par_GetParToHTML ("Feedback",Feedback,Cns_MAX_BYTES_TEXT); Par_GetParToHTML ("Feedback",Feedback,Cns_MAX_BYTES_TEXT);
/***** Get media associated to the stem (action, file and title) *****/ /***** Get media associated to the stem (action, file and title) *****/
Gbl.Test.Question.Media.Width = Tst_IMAGE_SAVED_MAX_WIDTH; Question->Media.Width = Tst_IMAGE_SAVED_MAX_WIDTH;
Gbl.Test.Question.Media.Height = Tst_IMAGE_SAVED_MAX_HEIGHT; Question->Media.Height = Tst_IMAGE_SAVED_MAX_HEIGHT;
Gbl.Test.Question.Media.Quality = Tst_IMAGE_SAVED_QUALITY; Question->Media.Quality = Tst_IMAGE_SAVED_QUALITY;
Med_GetMediaFromForm (Gbl.Hierarchy.Crs.CrsCod,QstCod, Med_GetMediaFromForm (Gbl.Hierarchy.Crs.CrsCod,QstCod,
-1, // < 0 ==> the image associated to the stem -1, // < 0 ==> the image associated to the stem
&Gbl.Test.Question.Media, &Question->Media,
Tst_GetMediaFromDB, Tst_GetMediaFromDB,
NULL); NULL);
Ale_ShowAlerts (NULL); Ale_ShowAlerts (NULL);
/***** Get answers *****/ /***** Get answers *****/
Gbl.Test.Question.Shuffle = false; Question->Shuffle = false;
switch (Gbl.Test.AnswerType) switch (Gbl.Test.AnswerType)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
@ -6059,7 +6079,7 @@ static long Tst_GetQstFromForm (char *Stem,char *Feedback)
case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_UNIQUE_CHOICE:
case Tst_ANS_MULTIPLE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE:
/* Get shuffle */ /* Get shuffle */
Gbl.Test.Question.Shuffle = Par_GetParToBool ("Shuffle"); Question->Shuffle = Par_GetParToBool ("Shuffle");
/* falls through */ /* falls through */
/* no break */ /* no break */
case Tst_ANS_TEXT: case Tst_ANS_TEXT:
@ -6146,10 +6166,10 @@ static long Tst_GetQstFromForm (char *Stem,char *Feedback)
NumTag++) NumTag++)
if (Gbl.Test.Tags.Txt[NumTag][0]) if (Gbl.Test.Tags.Txt[NumTag][0])
Gbl.Test.Tags.Num++; Gbl.Test.Tags.Num++;
Gbl.Test.Question.Stem.Text = Stem; Question->Stem.Text = Stem;
Gbl.Test.Question.Stem.Length = strlen (Gbl.Test.Question.Stem.Text); Question->Stem.Length = strlen (Question->Stem.Text);
Gbl.Test.Question.Feedback.Text = Feedback; Question->Feedback.Text = Feedback;
Gbl.Test.Question.Feedback.Length = strlen (Gbl.Test.Question.Feedback.Text); Question->Feedback.Length = strlen (Question->Feedback.Text);
return QstCod; return QstCod;
} }
@ -6161,7 +6181,7 @@ static long Tst_GetQstFromForm (char *Stem,char *Feedback)
// Counts Gbl.Test.Answer.NumOptions // Counts Gbl.Test.Answer.NumOptions
// Computes Gbl.Test.Answer.Integer and Gbl.Test.Answer.FloatingPoint[0..1] // 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_at_least_one_tag_for_the_question;
extern const char *Txt_You_must_type_the_stem_of_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*****/ /***** 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); Ale_ShowAlert (Ale_WARNING,Txt_You_must_type_the_stem_of_the_question);
return false; return false;
@ -6343,7 +6363,7 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (void)
/*********** Check if a test question already exists in database *************/ /*********** 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]; extern const char *Tst_StrAnswerTypesDB[Tst_NUM_ANS_TYPES];
MYSQL_RES *mysql_res_qst; MYSQL_RES *mysql_res_qst;
@ -6366,7 +6386,7 @@ bool Tst_CheckIfQuestionExistsInDB (void)
" WHERE CrsCod=%ld AND AnsType='%s' AND Stem='%s'", " WHERE CrsCod=%ld AND AnsType='%s' AND Stem='%s'",
Gbl.Hierarchy.Crs.CrsCod, Gbl.Hierarchy.Crs.CrsCod,
Tst_StrAnswerTypesDB[Gbl.Test.AnswerType], 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 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 */ /* 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; unsigned NumOpt;
long CurrentMedCodInDB; long CurrentMedCodInDB;
@ -6457,7 +6478,7 @@ static void Tst_MoveMediaToDefinitiveDirectories (long QstCod)
/***** Media associated to question stem *****/ /***** Media associated to question stem *****/
CurrentMedCodInDB = Tst_GetMedCodFromDB (Gbl.Hierarchy.Crs.CrsCod,QstCod, CurrentMedCodInDB = Tst_GetMedCodFromDB (Gbl.Hierarchy.Crs.CrsCod,QstCod,
-1L); // Get current media code associated to stem -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 *****/ /****** Move media associated to answers *****/
if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE || 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 **********/ /******** 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 *****/ /***** Insert or update question in the table of questions *****/
QstCod = Tst_InsertOrUpdateQstIntoDB (QstCod); QstCod = Tst_InsertOrUpdateQstIntoDB (QstCod,Question);
if (QstCod > 0) if (QstCod > 0)
{ {
/***** Insert tags in the tags table *****/ /***** Insert tags in the tags table *****/
@ -6882,7 +6904,8 @@ long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod)
/*********** Insert or update question in the table of questions *************/ /*********** 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 if (QstCod < 0) // It's a new question
{ {
@ -6890,21 +6913,33 @@ static long Tst_InsertOrUpdateQstIntoDB (long QstCod)
QstCod = QstCod =
DB_QueryINSERTandReturnCode ("can not create question", DB_QueryINSERTandReturnCode ("can not create question",
"INSERT INTO tst_questions" "INSERT INTO tst_questions"
" (CrsCod,EditTime,AnsType,Shuffle," " (CrsCod,"
"Stem,Feedback,MedCod," "EditTime,"
"NumHits,Score)" "AnsType,"
"Shuffle,"
"Stem,"
"Feedback,"
"MedCod,"
"NumHits,"
"Score)"
" VALUES" " VALUES"
" (%ld,NOW(),'%s','%c'," " (%ld," // CrsCod
"'%s','%s',%ld," "NOW()," // EditTime
"0,0)", "'%s'," // AnsType
"'%c'," // Shuffle
"'%s'," // Stem
"'%s'," // Feedback
"%ld," // MedCod
"0," // NumHits
"0)", // Score
Gbl.Hierarchy.Crs.CrsCod, Gbl.Hierarchy.Crs.CrsCod,
Tst_StrAnswerTypesDB[Gbl.Test.AnswerType], Tst_StrAnswerTypesDB[Gbl.Test.AnswerType],
Gbl.Test.Question.Shuffle ? 'Y' : Question->Shuffle ? 'Y' :
'N', 'N',
Gbl.Test.Question.Stem.Text, Question->Stem.Text,
Gbl.Test.Question.Feedback.Text ? Gbl.Test.Question.Feedback.Text : Question->Feedback.Text ? Question->Feedback.Text :
"", "",
Gbl.Test.Question.Media.MedCod); Question->Media.MedCod);
} }
else // It's an existing question else // It's an existing question
{ {
@ -6912,16 +6947,20 @@ static long Tst_InsertOrUpdateQstIntoDB (long QstCod)
/* Update question in database */ /* Update question in database */
DB_QueryUPDATE ("can not update question", DB_QueryUPDATE ("can not update question",
"UPDATE tst_questions" "UPDATE tst_questions"
" SET EditTime=NOW(),AnsType='%s',Shuffle='%c'," " SET EditTime=NOW(),"
"Stem='%s',Feedback='%s',MedCod=%ld" "AnsType='%s',"
"Shuffle='%c',"
"Stem='%s',"
"Feedback='%s',"
"MedCod=%ld"
" WHERE QstCod=%ld AND CrsCod=%ld", " WHERE QstCod=%ld AND CrsCod=%ld",
Tst_StrAnswerTypesDB[Gbl.Test.AnswerType], Tst_StrAnswerTypesDB[Gbl.Test.AnswerType],
Gbl.Test.Question.Shuffle ? 'Y' : Question->Shuffle ? 'Y' :
'N', 'N',
Gbl.Test.Question.Stem.Text, Question->Stem.Text,
Gbl.Test.Question.Feedback.Text ? Gbl.Test.Question.Feedback.Text : Question->Feedback.Text ? Question->Feedback.Text :
"", "",
Gbl.Test.Question.Media.MedCod, Question->Media.MedCod,
QstCod,Gbl.Hierarchy.Crs.CrsCod); QstCod,Gbl.Hierarchy.Crs.CrsCod);
/* Remove answers and tags from this test question */ /* Remove answers and tags from this test question */

View File

@ -147,7 +147,9 @@ void Tst_ShowTagList (unsigned NumTags,MYSQL_RES *mysql_res);
void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions, void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions,
struct UsrData *UsrDat, struct UsrData *UsrDat,
unsigned NumQst,long QstCod,MYSQL_ROW row, unsigned NumQst,
long QstCod,
MYSQL_ROW row,
unsigned Visibility, unsigned Visibility,
double *ScoreThisQst,bool *AnswerIsNotBlank); double *ScoreThisQst,bool *AnswerIsNotBlank);
void Tst_WriteQstStem (const char *Stem,const char *ClassStem,bool Visible); 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_ReceiveConfigTst (void);
void Tst_ShowFormEditOneQst (void); void Tst_ShowFormEditOneQst (void);
void Tst_QstConstructor (void); void Tst_QstConstructor (struct Tst_Question *Question);
void Tst_QstDestructor (void); void Tst_QstDestructor (struct Tst_Question *Question);
int Tst_AllocateTextChoiceAnswer (unsigned NumOpt); int Tst_AllocateTextChoiceAnswer (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 (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); long Tst_GetIntAnsFromStr (char *Str);
@ -218,7 +220,8 @@ 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); long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod,
const struct Tst_Question *Question);
void Tst_RemoveCrsTests (long CrsCod); void Tst_RemoveCrsTests (long CrsCod);

View File

@ -79,6 +79,7 @@ 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_Question *Question,
bool QuestionExists); bool QuestionExists);
/*****************************************************************************/ /*****************************************************************************/
@ -528,6 +529,7 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
struct XMLAttribute *Attribute; struct XMLAttribute *Attribute;
bool AnswerTypeFound; bool AnswerTypeFound;
bool QuestionExists; bool QuestionExists;
struct Tst_Question Question;
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];
@ -571,7 +573,7 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
if (!strcmp (QuestionElem->TagName,"question")) if (!strcmp (QuestionElem->TagName,"question"))
{ {
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (); Tst_QstConstructor (&Question);
/* Get type of questions (in mandatory attribute "type") */ /* Get type of questions (in mandatory attribute "type") */
AnswerTypeFound = false; AnswerTypeFound = false;
@ -623,8 +625,8 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML, Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML,
Stem,Cns_MAX_BYTES_TEXT,true); Stem,Cns_MAX_BYTES_TEXT,true);
Gbl.Test.Question.Stem.Text = Stem; Question.Stem.Text = Stem;
Gbl.Test.Question.Stem.Length = strlen (Stem); Question.Stem.Length = strlen (Stem);
} }
break; // Only first element "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, Str_ChangeFormat (Str_FROM_TEXT,Str_TO_HTML,
Feedback,Cns_MAX_BYTES_TEXT,true); Feedback,Cns_MAX_BYTES_TEXT,true);
Gbl.Test.Question.Feedback.Text = Feedback; Question.Feedback.Text = Feedback;
Gbl.Test.Question.Feedback.Length = strlen (Feedback); Question.Feedback.Length = strlen (Feedback);
} }
break; // Only first element "feedback" break; // Only first element "feedback"
} }
/* Get shuffle. By default, shuffle is false. */ /* Get shuffle. By default, shuffle is false. */
Gbl.Test.Question.Shuffle = false; Question.Shuffle = false;
for (AnswerElem = QuestionElem->FirstChild; for (AnswerElem = QuestionElem->FirstChild;
AnswerElem != NULL; AnswerElem != NULL;
AnswerElem = AnswerElem->NextBrother) AnswerElem = AnswerElem->NextBrother)
@ -664,7 +666,7 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
Attribute = Attribute->Next) Attribute = Attribute->Next)
if (!strcmp (Attribute->AttributeName,"shuffle")) 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 attribute "shuffle"
} }
break; // Only first element "answer" break; // Only first element "answer"
@ -674,22 +676,22 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
TsI_GetAnswerFromXML (AnswerElem); TsI_GetAnswerFromXML (AnswerElem);
/* Make sure that tags, text and answer are not empty */ /* Make sure that tags, text and answer are not empty */
if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions ()) if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question))
{ {
/* Check if question already exists in database */ /* Check if question already exists in database */
QuestionExists = Tst_CheckIfQuestionExistsInDB (); QuestionExists = Tst_CheckIfQuestionExistsInDB (&Question);
/* Write row with this imported 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 a new question ==> insert question, tags and answer in the database *****/
if (!QuestionExists) if (!QuestionExists)
if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L) <= 0) if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L,&Question) <= 0)
Lay_ShowErrorAndExit ("Can not create question."); Lay_ShowErrorAndExit ("Can not create question.");
} }
/***** Destroy test 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, static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
struct XMLElement *FeedbackElem, struct XMLElement *FeedbackElem,
const struct Tst_Question *Question,
bool QuestionExists) bool QuestionExists)
{ {
extern const char *Txt_Existing_question; 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 || if (Gbl.Test.AnswerType == Tst_ANS_UNIQUE_CHOICE ||
Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE) Gbl.Test.AnswerType == Tst_ANS_MULTIPLE_CHOICE)
/* Put an icon that indicates whether shuffle is enabled or not */ /* 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, Ico_PutIcon ("check.svg",Txt_TST_Answer_given_by_the_teachers,
QuestionExists ? "ICO_HIDDEN ICO16x16" : QuestionExists ? "ICO_HIDDEN ICO16x16" :
"ICO16x16"); "ICO16x16");

View File

@ -901,7 +901,8 @@ void TsR_ShowTestResult (struct UsrData *UsrDat,
/***** Write questions and answers *****/ /***** Write questions and answers *****/
Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_RESULT, Tst_WriteQstAndAnsTest (Tst_SHOW_TEST_RESULT,
UsrDat, UsrDat,
NumQst,Gbl.Test.QstCodes[NumQst],row, NumQst,Gbl.Test.QstCodes[NumQst],
row,
Visibility, Visibility,
&ScoreThisQst, // Not used here &ScoreThisQst, // Not used here
&AnswerIsNotBlank); // Not used here &AnswerIsNotBlank); // Not used here