Version 21.46.1: Oct 26, 2021 Queries moved to module swad_test_database.

This commit is contained in:
acanas 2021-10-26 17:33:20 +02:00
parent 4120cb75b7
commit d38b53b196
21 changed files with 274 additions and 244 deletions

View File

@ -602,13 +602,14 @@ TODO: FIX BUG, URGENT! En las fechas como par
TODO: En las encuestas, que los estudiantes no puedan ver los resultados hasta que no finalice el plazo. TODO: En las encuestas, que los estudiantes no puedan ver los resultados hasta que no finalice el plazo.
*/ */
#define Log_PLATFORM_VERSION "SWAD 21.46 (2021-10-26)" #define Log_PLATFORM_VERSION "SWAD 21.46.1 (2021-10-26)"
#define CSS_FILE "swad20.45.css" #define CSS_FILE "swad20.45.css"
#define JS_FILE "swad20.69.1.js" #define JS_FILE "swad20.69.1.js"
/* /*
TODO: Rename CENTRE to CENTER in help wiki. TODO: Rename CENTRE to CENTER in help wiki.
TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams
Version 21.46.1: Oct 26, 2021 Queries moved to module swad_test_database. (? lines)
Version 21.46: Oct 26, 2021 New module swad_test_database for database queries related to self-assessment tests. (321036 lines) Version 21.46: Oct 26, 2021 New module swad_test_database for database queries related to self-assessment tests. (321036 lines)
Version 21.45.1: Oct 25, 2021 Code refactoring in test questions. (320932 lines) Version 21.45.1: Oct 25, 2021 Code refactoring in test questions. (320932 lines)
Version 21.45: Oct 25, 2021 Functions moved to module swad_question. (320930 lines) Version 21.45: Oct 25, 2021 Functions moved to module swad_question. (320930 lines)

View File

@ -63,6 +63,7 @@
#include "swad_setting_database.h" #include "swad_setting_database.h"
#include "swad_survey.h" #include "swad_survey.h"
#include "swad_test.h" #include "swad_test.h"
#include "swad_test_database.h"
/*****************************************************************************/ /*****************************************************************************/
/************** External global variables from others modules ****************/ /************** External global variables from others modules ****************/
@ -1838,8 +1839,11 @@ static void Crs_EmptyCourseCompletely (long CrsCod)
/***** Remove all exams in the course *****/ /***** Remove all exams in the course *****/
Exa_RemoveCrsExams (CrsCod); Exa_RemoveCrsExams (CrsCod);
/***** Remove all tests in the course *****/ /***** Remove all test prints made in the course *****/
Tst_RemoveCrsTests (CrsCod); TstPrn_RemoveCrsPrints (CrsCod);
/***** Remove test configuration of the course *****/
Tst_DB_RemoveTstConfig (CrsCod);
/***** Remove all questions in the course *****/ /***** Remove all questions in the course *****/
Qst_RemoveCrsQsts (CrsCod); Qst_RemoveCrsQsts (CrsCod);

View File

@ -65,6 +65,15 @@ void Err_NotEnoughMemoryExit (void)
Err_ShowErrorAndExit ("Not enough memory."); Err_ShowErrorAndExit ("Not enough memory.");
} }
/*****************************************************************************/
/********** Write error message and exit when not space for query ************/
/*****************************************************************************/
void Err_QuerySizeExceededExit (void)
{
Err_ShowErrorAndExit ("Query size exceeded.");
}
/*****************************************************************************/ /*****************************************************************************/
/************* Write error message and exit when wrong action ****************/ /************* Write error message and exit when wrong action ****************/
/*****************************************************************************/ /*****************************************************************************/

View File

@ -40,6 +40,7 @@
/*****************************************************************************/ /*****************************************************************************/
void Err_NotEnoughMemoryExit (void); void Err_NotEnoughMemoryExit (void);
void Err_QuerySizeExceededExit (void);
void Err_WrongActionExit (void); void Err_WrongActionExit (void);
void Err_WrongScopeExit (void); void Err_WrongScopeExit (void);
void Err_WrongCountrExit (void); void Err_WrongCountrExit (void);

View File

@ -181,7 +181,7 @@ static void ExaRes_ListMyResultsInCrs (struct Exa_Exams *Exams)
ExaRes_ShowHeaderResults (Usr_ME); ExaRes_ShowHeaderResults (Usr_ME);
/***** List my sessions results in the current course *****/ /***** List my sessions results in the current course *****/
TstCfg_GetConfigFromDB (); // Get feedback type TstCfg_GetConfig (); // Get feedback type
ExaRes_BuildExamsSelectedCommas (Exams,&ExamsSelectedCommas); ExaRes_BuildExamsSelectedCommas (Exams,&ExamsSelectedCommas);
ExaRes_ShowResults (Exams,Usr_ME,-1L,-1L,ExamsSelectedCommas); ExaRes_ShowResults (Exams,Usr_ME,-1L,-1L,ExamsSelectedCommas);
free (ExamsSelectedCommas); free (ExamsSelectedCommas);
@ -235,7 +235,7 @@ static void ExaRes_ListMyResultsInExa (struct Exa_Exams *Exams,long ExaCod)
ExaRes_ShowHeaderResults (Usr_ME); ExaRes_ShowHeaderResults (Usr_ME);
/***** List my sessions results in exam *****/ /***** List my sessions results in exam *****/
TstCfg_GetConfigFromDB (); // Get feedback type TstCfg_GetConfig (); // Get feedback type
ExaRes_ShowResults (Exams,Usr_ME,-1L,ExaCod,NULL); ExaRes_ShowResults (Exams,Usr_ME,-1L,ExaCod,NULL);
} }
@ -287,7 +287,7 @@ static void ExaRes_ListMyResultsInSes (struct Exa_Exams *Exams,long SesCod)
ExaRes_ShowHeaderResults (Usr_ME); ExaRes_ShowHeaderResults (Usr_ME);
/***** List my sessions results in exam *****/ /***** List my sessions results in exam *****/
TstCfg_GetConfigFromDB (); // Get feedback type TstCfg_GetConfig (); // Get feedback type
ExaRes_ShowResults (Exams,Usr_ME,SesCod,-1L,NULL); ExaRes_ShowResults (Exams,Usr_ME,SesCod,-1L,NULL);
} }

View File

@ -1274,7 +1274,7 @@ void ExaSet_AddQstsToSet (void)
ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS); ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS);
/* Check number of questions */ /* Check number of questions */
if (Tst_CountNumQuestionsInList (Exams.ListQuestions)) // If questions selected... if (Qst_CountNumQuestionsInList (Exams.ListQuestions)) // If questions selected...
{ {
/***** Insert questions in database *****/ /***** Insert questions in database *****/
Ptr = Exams.ListQuestions; Ptr = Exams.ListQuestions;

View File

@ -1897,7 +1897,7 @@ void Gam_AddQstsToGame (void)
/* Check number of questions */ /* Check number of questions */
NumQstsAdded = 0; NumQstsAdded = 0;
if (Tst_CountNumQuestionsInList (Games.ListQuestions)) // If questions selected... if (Qst_CountNumQuestionsInList (Games.ListQuestions)) // If questions selected...
{ {
/***** Insert questions in database *****/ /***** Insert questions in database *****/
Ptr = Games.ListQuestions; Ptr = Games.ListQuestions;

View File

@ -147,7 +147,7 @@ static void MchRes_ListMyMchResultsInCrs (struct Gam_Games *Games)
MchRes_ShowHeaderMchResults (Usr_ME); MchRes_ShowHeaderMchResults (Usr_ME);
/***** List my matches results in the current course *****/ /***** List my matches results in the current course *****/
TstCfg_GetConfigFromDB (); // Get feedback type TstCfg_GetConfig (); // Get feedback type
MchRes_BuildGamesSelectedCommas (Games,&GamesSelectedCommas); MchRes_BuildGamesSelectedCommas (Games,&GamesSelectedCommas);
MchRes_ShowMchResults (Games,Usr_ME,-1L,-1L,GamesSelectedCommas); MchRes_ShowMchResults (Games,Usr_ME,-1L,-1L,GamesSelectedCommas);
free (GamesSelectedCommas); free (GamesSelectedCommas);
@ -197,7 +197,7 @@ static void MchRes_ListMyMchResultsInGam (struct Gam_Games *Games,long GamCod)
MchRes_ShowHeaderMchResults (Usr_ME); MchRes_ShowHeaderMchResults (Usr_ME);
/***** List my matches results in game *****/ /***** List my matches results in game *****/
TstCfg_GetConfigFromDB (); // Get feedback type TstCfg_GetConfig (); // Get feedback type
MchRes_ShowMchResults (Games,Usr_ME,-1L,GamCod,NULL); MchRes_ShowMchResults (Games,Usr_ME,-1L,GamCod,NULL);
} }
@ -249,7 +249,7 @@ static void MchRes_ListMyMchResultsInMch (struct Gam_Games *Games,long MchCod)
MchRes_ShowHeaderMchResults (Usr_ME); MchRes_ShowHeaderMchResults (Usr_ME);
/***** List my matches results in game *****/ /***** List my matches results in game *****/
TstCfg_GetConfigFromDB (); // Get feedback type TstCfg_GetConfig (); // Get feedback type
MchRes_ShowMchResults (Games,Usr_ME,MchCod,-1L,NULL); MchRes_ShowMchResults (Games,Usr_ME,MchCod,-1L,NULL);
} }

View File

@ -1692,7 +1692,7 @@ void Qst_GetQuestions (struct Qst_Questions *Questions,MYSQL_RES **mysql_res)
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tag_MAX_BYTES_TAG); Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tag_MAX_BYTES_TAG);
LengthQuery = LengthQuery + 35 + strlen (TagText) + 1; LengthQuery = LengthQuery + 35 + strlen (TagText) + 1;
if (LengthQuery > Qst_MAX_BYTES_QUERY_QUESTIONS - 256) if (LengthQuery > Qst_MAX_BYTES_QUERY_QUESTIONS - 256)
Err_ShowErrorAndExit ("Query size exceed."); Err_QuerySizeExceededExit ();
Str_Concat (Query, Str_Concat (Query,
NumItemInList ? " OR tst_tags.TagTxt='" : NumItemInList ? " OR tst_tags.TagTxt='" :
" AND (tst_tags.TagTxt='", " AND (tst_tags.TagTxt='",
@ -1716,7 +1716,7 @@ void Qst_GetQuestions (struct Qst_Questions *Questions,MYSQL_RES **mysql_res)
AnsType = Qst_ConvertFromUnsignedStrToAnsTyp (UnsignedStr); AnsType = Qst_ConvertFromUnsignedStrToAnsTyp (UnsignedStr);
LengthQuery = LengthQuery + 35 + strlen (Qst_DB_StrAnswerTypes[AnsType]) + 1; LengthQuery = LengthQuery + 35 + strlen (Qst_DB_StrAnswerTypes[AnsType]) + 1;
if (LengthQuery > Qst_MAX_BYTES_QUERY_QUESTIONS - 256) if (LengthQuery > Qst_MAX_BYTES_QUERY_QUESTIONS - 256)
Err_ShowErrorAndExit ("Query size exceed."); Err_QuerySizeExceededExit ();
Str_Concat (Query, Str_Concat (Query,
NumItemInList ? " OR tst_questions.AnsType='" : NumItemInList ? " OR tst_questions.AnsType='" :
" AND (tst_questions.AnsType='", " AND (tst_questions.AnsType='",
@ -3757,6 +3757,50 @@ void Qst_InsertAnswersIntoDB (struct Qst_Question *Question)
} }
} }
/*****************************************************************************/
/**** Count the number of types of answers in the list of types of answers ***/
/*****************************************************************************/
unsigned Qst_CountNumAnswerTypesInList (const struct Qst_AnswerTypes *AnswerTypes)
{
const char *Ptr;
unsigned NumAnsTypes = 0;
char UnsignedStr[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
/***** Go over the list of answer types counting the number of types of answer *****/
Ptr = AnswerTypes->List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,UnsignedStr,Cns_MAX_DECIMAL_DIGITS_UINT);
Qst_ConvertFromUnsignedStrToAnsTyp (UnsignedStr);
NumAnsTypes++;
}
return NumAnsTypes;
}
/*****************************************************************************/
/**** Count the number of questions in the list of selected question codes ***/
/*****************************************************************************/
unsigned Qst_CountNumQuestionsInList (const char *ListQuestions)
{
const char *Ptr;
unsigned NumQuestions = 0;
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
long QstCod;
/***** Go over list of questions counting the number of questions *****/
Ptr = ListQuestions;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
if (sscanf (LongStr,"%ld",&QstCod) != 1)
Err_WrongQuestionExit ();
NumQuestions++;
}
return NumQuestions;
}
/*****************************************************************************/ /*****************************************************************************/
/********************* Remove all questions in a course **********************/ /********************* Remove all questions in a course **********************/
/*****************************************************************************/ /*****************************************************************************/

View File

@ -268,6 +268,9 @@ void Qst_InsertOrUpdateQstTagsAnsIntoDB (struct Qst_Question *Question);
void Qst_InsertOrUpdateQstIntoDB (struct Qst_Question *Question); void Qst_InsertOrUpdateQstIntoDB (struct Qst_Question *Question);
void Qst_InsertAnswersIntoDB (struct Qst_Question *Question); void Qst_InsertAnswersIntoDB (struct Qst_Question *Question);
unsigned Qst_CountNumAnswerTypesInList (const struct Qst_AnswerTypes *AnswerTypes);
unsigned Qst_CountNumQuestionsInList (const char *ListQuestions);
void Qst_RemoveCrsQsts (long CrsCod); void Qst_RemoveCrsQsts (long CrsCod);
void Qst_DB_RemAnsFromQst (long QstCod); void Qst_DB_RemAnsFromQst (long QstCod);
void Qst_RemoveMediaFromStemOfQst (long CrsCod,long QstCod); void Qst_RemoveMediaFromStemOfQst (long CrsCod,long QstCod);

View File

@ -430,7 +430,7 @@ unsigned Sta_DB_GetHits (MYSQL_RES **mysql_res,
{ {
LengthQuery = LengthQuery + 25 + 10 + 1; LengthQuery = LengthQuery + 25 + 10 + 1;
if (LengthQuery > Sta_DB_MAX_BYTES_QUERY - 128) if (LengthQuery > Sta_DB_MAX_BYTES_QUERY - 128)
Err_ShowErrorAndExit ("Query is too large."); Err_QuerySizeExceededExit ();
sprintf (SubQuery, sprintf (SubQuery,
NumUsr ? " OR %s.UsrCod=%ld" : NumUsr ? " OR %s.UsrCod=%ld" :
" AND (%s.UsrCod=%ld", " AND (%s.UsrCod=%ld",

View File

@ -277,6 +277,27 @@ void Tag_InsertTagsIntoDB (long QstCod,const struct Tag_Tags *Tags)
} }
} }
/*****************************************************************************/
/***************** Count number of tags in the list of tags ******************/
/*****************************************************************************/
unsigned Tag_CountNumTagsInList (const struct Tag_Tags *Tags)
{
const char *Ptr;
unsigned NumTags = 0;
char TagText[Tag_MAX_BYTES_TAG + 1];
/***** Go over the list of tags counting the number of tags *****/
Ptr = Tags->List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tag_MAX_BYTES_TAG);
NumTags++;
}
return NumTags;
}
/*****************************************************************************/ /*****************************************************************************/
/********************* Show a form to select test tags ***********************/ /********************* Show a form to select test tags ***********************/
/*****************************************************************************/ /*****************************************************************************/

View File

@ -67,6 +67,8 @@ void Tag_RenameTag (void);
void Tag_InsertTagsIntoDB (long QstCod,const struct Tag_Tags *Tags); void Tag_InsertTagsIntoDB (long QstCod,const struct Tag_Tags *Tags);
unsigned Tag_CountNumTagsInList (const struct Tag_Tags *Tags);
void Tag_ShowFormSelTags (const struct Tag_Tags *Tags, void Tag_ShowFormSelTags (const struct Tag_Tags *Tags,
MYSQL_RES *mysql_res, MYSQL_RES *mysql_res,
bool ShowOnlyEnabledTags); bool ShowOnlyEnabledTags);

View File

@ -92,19 +92,15 @@ extern struct Globals Gbl;
static void Tst_ShowFormRequestTest (struct Qst_Questions *Questions); static void Tst_ShowFormRequestTest (struct Qst_Questions *Questions);
static void TstPrn_GetAnswersFromForm (struct TstPrn_Print *Print);
static bool Tst_CheckIfNextTstAllowed (void); static bool Tst_CheckIfNextTstAllowed (void);
static void Tst_GetQuestionsForNewTestFromDB (struct Qst_Questions *Questions, static void Tst_GetQuestionsForNewTest (struct Qst_Questions *Questions,
struct TstPrn_Print *Print); struct TstPrn_Print *Print);
static void Tst_GenerateChoiceIndexes (struct TstPrn_PrintedQuestion *PrintedQuestion, static void Tst_GenerateChoiceIndexes (struct TstPrn_PrintedQuestion *PrintedQuestion,
bool Shuffle); bool Shuffle);
static unsigned Tst_GetParamNumTst (void); static unsigned Tst_GetParamNumTst (void);
static unsigned Tst_GetParamNumQsts (void); static unsigned Tst_GetParamNumQsts (void);
static unsigned Tst_CountNumTagsInList (const struct Tag_Tags *Tags);
static int Tst_CountNumAnswerTypesInList (const struct Qst_AnswerTypes *AnswerTypes);
/*****************************************************************************/ /*****************************************************************************/
/********************* Request a self-assessment test ************************/ /********************* Request a self-assessment test ************************/
@ -114,13 +110,13 @@ void Tst_RequestTest (void)
{ {
struct Qst_Questions Questions; struct Qst_Questions Questions;
/***** Create test *****/ /***** Create questions *****/
Qst_Constructor (&Questions); Qst_Constructor (&Questions);
/***** Show form to generate a self-assessment test *****/ /***** Show form to generate a self-assessment test *****/
Tst_ShowFormRequestTest (&Questions); Tst_ShowFormRequestTest (&Questions);
/***** Destroy test *****/ /***** Destroy questions *****/
Qst_Destructor (&Questions); Qst_Destructor (&Questions);
} }
@ -138,7 +134,7 @@ static void Tst_ShowFormRequestTest (struct Qst_Questions *Questions)
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
/***** Read test configuration from database *****/ /***** Read test configuration from database *****/
TstCfg_GetConfigFromDB (); TstCfg_GetConfig ();
/***** Begin box *****/ /***** Begin box *****/
Box_BoxBegin (NULL,Txt_Test, Box_BoxBegin (NULL,Txt_Test,
@ -219,7 +215,7 @@ void Tst_ShowNewTest (void)
Qst_Constructor (&Questions); Qst_Constructor (&Questions);
/***** Read test configuration from database *****/ /***** Read test configuration from database *****/
TstCfg_GetConfigFromDB (); TstCfg_GetConfig ();
if (Tst_CheckIfNextTstAllowed ()) if (Tst_CheckIfNextTstAllowed ())
{ {
@ -228,7 +224,7 @@ void Tst_ShowNewTest (void)
{ {
/***** Get questions *****/ /***** Get questions *****/
TstPrn_ResetPrint (&Print); TstPrn_ResetPrint (&Print);
Tst_GetQuestionsForNewTestFromDB (&Questions,&Print); Tst_GetQuestionsForNewTest (&Questions,&Print);
if (Print.NumQsts.All) if (Print.NumQsts.All)
{ {
/***** Increase number of exams generated (answered or not) by me *****/ /***** Increase number of exams generated (answered or not) by me *****/
@ -273,7 +269,7 @@ void Tst_ReceiveTestDraft (void)
struct TstPrn_Print Print; struct TstPrn_Print Print;
/***** Read test configuration from database *****/ /***** Read test configuration from database *****/
TstCfg_GetConfigFromDB (); TstCfg_GetConfig ();
/***** Get basic parameters of the exam *****/ /***** Get basic parameters of the exam *****/
/* Get test print code from form */ /* Get test print code from form */
@ -329,7 +325,7 @@ void Tst_AssessTest (void)
struct TstPrn_Print Print; struct TstPrn_Print Print;
/***** Read test configuration from database *****/ /***** Read test configuration from database *****/
TstCfg_GetConfigFromDB (); TstCfg_GetConfig ();
/***** Get basic parameters of the exam *****/ /***** Get basic parameters of the exam *****/
/* Get test print code from form */ /* Get test print code from form */
@ -401,28 +397,6 @@ void Tst_AssessTest (void)
} }
} }
/*****************************************************************************/
/******** Get questions and answers from form to assess a test print *********/
/*****************************************************************************/
static void TstPrn_GetAnswersFromForm (struct TstPrn_Print *Print)
{
unsigned QstInd;
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
/***** Loop for every question getting user's answers *****/
for (QstInd = 0;
QstInd < Print->NumQsts.All;
QstInd++)
{
/* Get answers selected by user for this question */
snprintf (StrAns,sizeof (StrAns),"Ans%010u",QstInd);
Par_GetParMultiToText (StrAns,Print->PrintedQuestions[QstInd].StrAnswers,
Qst_MAX_BYTES_ANSWERS_ONE_QST); /* If answer type == T/F ==> " ", "T", "F"; if choice ==> "0", "2",... */
Par_ReplaceSeparatorMultipleByComma (Print->PrintedQuestions[QstInd].StrAnswers);
}
}
/*****************************************************************************/ /*****************************************************************************/
/************** Check minimum date-time of next access to test ***************/ /************** Check minimum date-time of next access to test ***************/
/*****************************************************************************/ /*****************************************************************************/
@ -518,21 +492,13 @@ void Tst_PutIconsTests (__attribute__((unused)) void *Args)
#define Tst_MAX_BYTES_QUERY_QUESTIONS (16 * 1024 - 1) #define Tst_MAX_BYTES_QUERY_QUESTIONS (16 * 1024 - 1)
static void Tst_GetQuestionsForNewTestFromDB (struct Qst_Questions *Questions, static void Tst_GetQuestionsForNewTest (struct Qst_Questions *Questions,
struct TstPrn_Print *Print) struct TstPrn_Print *Print)
{ {
extern const char *Qst_DB_StrAnswerTypes[Qst_NUM_ANS_TYPES];
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
char *Query = NULL;
long LengthQuery;
unsigned NumItemInList;
const char *Ptr;
char TagText[Tag_MAX_BYTES_TAG + 1];
char UnsignedStr[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
Qst_AnswerType_t AnswerType; Qst_AnswerType_t AnswerType;
bool Shuffle; bool Shuffle;
char StrNumQsts[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
unsigned QstInd; unsigned QstInd;
/***** Trivial check: number of questions *****/ /***** Trivial check: number of questions *****/
@ -540,96 +506,10 @@ static void Tst_GetQuestionsForNewTestFromDB (struct Qst_Questions *Questions,
Questions->NumQsts > TstCfg_MAX_QUESTIONS_PER_TEST) Questions->NumQsts > TstCfg_MAX_QUESTIONS_PER_TEST)
Err_ShowErrorAndExit ("Wrong number of questions."); Err_ShowErrorAndExit ("Wrong number of questions.");
/***** Allocate space for query *****/
if ((Query = malloc (Tst_MAX_BYTES_QUERY_QUESTIONS + 1)) == NULL)
Err_NotEnoughMemoryExit ();
/***** Select questions without hidden tags *****/
/* Begin query */
// Reject questions with any tag hidden
// Select only questions with tags
// DISTINCTROW is necessary to not repeat questions
snprintf (Query,Tst_MAX_BYTES_QUERY_QUESTIONS + 1,
"SELECT DISTINCTROW tst_questions.QstCod," // row[0]
"tst_questions.AnsType," // row[1]
"tst_questions.Shuffle" // row[2]
" FROM tst_questions,tst_question_tags,tst_tags"
" WHERE tst_questions.CrsCod=%ld"
" AND tst_questions.QstCod NOT IN"
" (SELECT tst_question_tags.QstCod"
" FROM tst_tags,tst_question_tags"
" WHERE tst_tags.CrsCod=%ld"
" AND tst_tags.TagHidden='Y'"
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
" AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod"
" AND tst_tags.CrsCod=%ld",
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Hierarchy.Crs.CrsCod);
if (!Questions->Tags.All) // User has not selected all the tags
{
/* Add selected tags */
LengthQuery = strlen (Query);
NumItemInList = 0;
Ptr = Questions->Tags.List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tag_MAX_BYTES_TAG);
LengthQuery = LengthQuery + 35 + strlen (TagText) + 1;
if (LengthQuery > Tst_MAX_BYTES_QUERY_QUESTIONS - 128)
Err_ShowErrorAndExit ("Query size exceed.");
Str_Concat (Query,
NumItemInList ? " OR tst_tags.TagTxt='" :
" AND (tst_tags.TagTxt='",
Tst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,TagText,Tst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,"'",Tst_MAX_BYTES_QUERY_QUESTIONS);
NumItemInList++;
}
Str_Concat (Query,")",Tst_MAX_BYTES_QUERY_QUESTIONS);
}
/* Add answer types selected */
if (!Questions->AnswerTypes.All)
{
LengthQuery = strlen (Query);
NumItemInList = 0;
Ptr = Questions->AnswerTypes.List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,UnsignedStr,Tag_MAX_BYTES_TAG);
AnswerType = Qst_ConvertFromUnsignedStrToAnsTyp (UnsignedStr);
LengthQuery = LengthQuery + 35 + strlen (Qst_DB_StrAnswerTypes[AnswerType]) + 1;
if (LengthQuery > Tst_MAX_BYTES_QUERY_QUESTIONS - 128)
Err_ShowErrorAndExit ("Query size exceed.");
Str_Concat (Query,
NumItemInList ? " OR tst_questions.AnsType='" :
" AND (tst_questions.AnsType='",
Tst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,Qst_DB_StrAnswerTypes[AnswerType],Tst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,"'",Tst_MAX_BYTES_QUERY_QUESTIONS);
NumItemInList++;
}
Str_Concat (Query,")",Tst_MAX_BYTES_QUERY_QUESTIONS);
}
/* End query */
Str_Concat (Query," ORDER BY RAND() LIMIT ",Tst_MAX_BYTES_QUERY_QUESTIONS);
snprintf (StrNumQsts,sizeof (StrNumQsts),"%u",Questions->NumQsts);
Str_Concat (Query,StrNumQsts,Tst_MAX_BYTES_QUERY_QUESTIONS);
/*
if (Gbl.Usrs.Me.Roles.LoggedRole == Rol_SYS_ADM)
Lay_ShowAlert (Lay_INFO,Query);
*/
/* Make the query */
Print->NumQsts.All =
Questions->NumQsts = (unsigned) DB_QuerySELECT (&mysql_res,"can not get questions",
"%s",
Query);
/***** Get questions and answers from database *****/ /***** Get questions and answers from database *****/
Print->NumQsts.All =
Questions->NumQsts = Tst_DB_GetQuestionsForNewTest (&mysql_res,Questions);
for (QstInd = 0; for (QstInd = 0;
QstInd < Print->NumQsts.All; QstInd < Print->NumQsts.All;
QstInd++) QstInd++)
@ -770,7 +650,7 @@ bool Tst_GetParamsTst (struct Qst_Questions *Questions,
Par_GetParMultiToText ("ChkTag",Questions->Tags.List,Tag_MAX_BYTES_TAGS_LIST); Par_GetParMultiToText ("ChkTag",Questions->Tags.List,Tag_MAX_BYTES_TAGS_LIST);
/* Check number of tags selected */ /* Check number of tags selected */
if (Tst_CountNumTagsInList (&Questions->Tags) == 0) // If no tags selected... if (Tag_CountNumTagsInList (&Questions->Tags) == 0) // If no tags selected...
{ // ...write alert { // ...write alert
Ale_ShowAlert (Ale_WARNING,Txt_You_must_select_one_ore_more_tags); Ale_ShowAlert (Ale_WARNING,Txt_You_must_select_one_ore_more_tags);
Error = true; Error = true;
@ -789,8 +669,8 @@ bool Tst_GetParamsTst (struct Qst_Questions *Questions,
Par_GetParMultiToText ("AnswerType",Questions->AnswerTypes.List,Qst_MAX_BYTES_LIST_ANSWER_TYPES); Par_GetParMultiToText ("AnswerType",Questions->AnswerTypes.List,Qst_MAX_BYTES_LIST_ANSWER_TYPES);
/* Check number of types of answer */ /* Check number of types of answer */
if (Tst_CountNumAnswerTypesInList (&Questions->AnswerTypes) == 0) // If no types of answer selected... if (Qst_CountNumAnswerTypesInList (&Questions->AnswerTypes) == 0) // If no types of answer selected...
{ // ...write warning alert { // ...write warning alert
Ale_ShowAlert (Ale_WARNING,Txt_You_must_select_one_ore_more_types_of_answer); Ale_ShowAlert (Ale_WARNING,Txt_You_must_select_one_ore_more_types_of_answer);
Error = true; Error = true;
} }
@ -869,84 +749,3 @@ static unsigned Tst_GetParamNumQsts (void)
(unsigned long) TstCfg_GetConfigMax (), (unsigned long) TstCfg_GetConfigMax (),
(unsigned long) TstCfg_GetConfigDef ()); (unsigned long) TstCfg_GetConfigDef ());
} }
/*****************************************************************************/
/***************** Count number of tags in the list of tags ******************/
/*****************************************************************************/
static unsigned Tst_CountNumTagsInList (const struct Tag_Tags *Tags)
{
const char *Ptr;
unsigned NumTags = 0;
char TagText[Tag_MAX_BYTES_TAG + 1];
/***** Go over the list of tags counting the number of tags *****/
Ptr = Tags->List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tag_MAX_BYTES_TAG);
NumTags++;
}
return NumTags;
}
/*****************************************************************************/
/**** Count the number of types of answers in the list of types of answers ***/
/*****************************************************************************/
static int Tst_CountNumAnswerTypesInList (const struct Qst_AnswerTypes *AnswerTypes)
{
const char *Ptr;
int NumAnsTypes = 0;
char UnsignedStr[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
/***** Go over the list of answer types counting the number of types of answer *****/
Ptr = AnswerTypes->List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,UnsignedStr,Cns_MAX_DECIMAL_DIGITS_UINT);
Qst_ConvertFromUnsignedStrToAnsTyp (UnsignedStr);
NumAnsTypes++;
}
return NumAnsTypes;
}
/*****************************************************************************/
/**** Count the number of questions in the list of selected question codes ***/
/*****************************************************************************/
unsigned Tst_CountNumQuestionsInList (const char *ListQuestions)
{
const char *Ptr;
unsigned NumQuestions = 0;
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
long QstCod;
/***** Go over list of questions counting the number of questions *****/
Ptr = ListQuestions;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG);
if (sscanf (LongStr,"%ld",&QstCod) != 1)
Err_WrongQuestionExit ();
NumQuestions++;
}
return NumQuestions;
}
/*****************************************************************************/
/************************* Remove all tests in a course **********************/
/*****************************************************************************/
void Tst_RemoveCrsTests (long CrsCod)
{
/***** Remove all test prints made in the course *****/
TstPrn_RemoveCrsPrints (CrsCod);
/***** Remove test configuration of the course *****/
DB_QueryDELETE ("can not remove configuration of tests of a course",
"DELETE FROM tst_config"
" WHERE CrsCod=%ld",
CrsCod);
}

View File

@ -69,8 +69,4 @@ void Tst_PutIconsTests (__attribute__((unused)) void *Args);
bool Tst_GetParamsTst (struct Qst_Questions *Questions, bool Tst_GetParamsTst (struct Qst_Questions *Questions,
Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions); Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions);
unsigned Tst_CountNumQuestionsInList (const char *ListQuestions);
void Tst_RemoveCrsTests (long CrsCod);
#endif #endif

View File

@ -179,7 +179,7 @@ static void TstCfg_ShowFormConfig (void)
Qst_Constructor (&Questions); Qst_Constructor (&Questions);
/***** Read test configuration from database *****/ /***** Read test configuration from database *****/
TstCfg_GetConfigFromDB (); TstCfg_GetConfig ();
/***** Begin box *****/ /***** Begin box *****/
Box_BoxBegin (NULL,Txt_Configure_tests, Box_BoxBegin (NULL,Txt_Configure_tests,
@ -313,7 +313,7 @@ static void TstCfg_PutInputFieldNumQsts (const char *Field,const char *Label,
/*************** Get configuration of test for current course ****************/ /*************** Get configuration of test for current course ****************/
/*****************************************************************************/ /*****************************************************************************/
void TstCfg_GetConfigFromDB (void) void TstCfg_GetConfig (void)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;

View File

@ -59,7 +59,7 @@ typedef enum
void TstCfg_CheckAndShowFormConfig (void); void TstCfg_CheckAndShowFormConfig (void);
bool TstCfg_CheckIfPluggableIsUnknownAndCrsHasTests (void); bool TstCfg_CheckIfPluggableIsUnknownAndCrsHasTests (void);
void TstCfg_GetConfigFromDB (void); void TstCfg_GetConfig (void);
void TstCfg_GetConfigFromRow (MYSQL_ROW row); void TstCfg_GetConfigFromRow (MYSQL_ROW row);
void TstCfg_ReceiveConfigTst (void); void TstCfg_ReceiveConfigTst (void);

View File

@ -33,14 +33,14 @@
// #include <stddef.h> // For NULL // #include <stddef.h> // For NULL
// #include <stdio.h> // For asprintf // #include <stdio.h> // For asprintf
// #include <stdlib.h> // For exit, system, malloc, free, etc // #include <stdlib.h> // For exit, system, malloc, free, etc
// #include <string.h> // For string functions #include <string.h> // For string functions
// #include <sys/stat.h> // For mkdir // #include <sys/stat.h> // For mkdir
// #include <sys/types.h> // For mkdir // #include <sys/types.h> // For mkdir
// #include "swad_action.h" // #include "swad_action.h"
// #include "swad_box.h" // #include "swad_box.h"
#include "swad_database.h" #include "swad_database.h"
// #include "swad_error.h" #include "swad_error.h"
// #include "swad_exam_set.h" // #include "swad_exam_set.h"
// #include "swad_figure.h" // #include "swad_figure.h"
// #include "swad_form.h" // #include "swad_form.h"
@ -52,12 +52,12 @@
// #include "swad_match.h" // #include "swad_match.h"
// #include "swad_media.h" // #include "swad_media.h"
// #include "swad_parameter.h" // #include "swad_parameter.h"
// #include "swad_question.h" #include "swad_question.h"
// #include "swad_question_import.h" // #include "swad_question_import.h"
// #include "swad_tag_database.h" // #include "swad_tag_database.h"
// #include "swad_test.h" // #include "swad_test.h"
#include "swad_test_config.h" #include "swad_test_config.h"
// #include "swad_test_print.h" #include "swad_test_print.h"
// #include "swad_test_visibility.h" // #include "swad_test_visibility.h"
// #include "swad_theme.h" // #include "swad_theme.h"
// #include "swad_user.h" // #include "swad_user.h"
@ -161,3 +161,124 @@ unsigned Tst_DB_GetNumPrintsGeneratedByMe (MYSQL_RES **mysql_res)
Gbl.Usrs.Me.UsrDat.UsrCod, Gbl.Usrs.Me.UsrDat.UsrCod,
Gbl.Hierarchy.Crs.CrsCod); Gbl.Hierarchy.Crs.CrsCod);
} }
/*****************************************************************************/
/************** Get questions for a new test from the database ***************/
/*****************************************************************************/
#define Tst_MAX_BYTES_QUERY_QUESTIONS (16 * 1024 - 1)
unsigned Tst_DB_GetQuestionsForNewTest (MYSQL_RES **mysql_res,
const struct Qst_Questions *Questions)
{
extern const char *Qst_DB_StrAnswerTypes[Qst_NUM_ANS_TYPES];
char *Query = NULL;
long LengthQuery;
unsigned NumItemInList;
const char *Ptr;
char TagText[Tag_MAX_BYTES_TAG + 1];
char UnsignedStr[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
Qst_AnswerType_t AnswerType;
char StrNumQsts[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
/***** Allocate space for query *****/
if ((Query = malloc (Tst_MAX_BYTES_QUERY_QUESTIONS + 1)) == NULL)
Err_NotEnoughMemoryExit ();
/***** Select questions without hidden tags *****/
/* Begin query */
// Reject questions with any tag hidden
// Select only questions with tags
// DISTINCTROW is necessary to not repeat questions
snprintf (Query,Tst_MAX_BYTES_QUERY_QUESTIONS + 1,
"SELECT DISTINCTROW tst_questions.QstCod," // row[0]
"tst_questions.AnsType," // row[1]
"tst_questions.Shuffle" // row[2]
" FROM tst_questions,tst_question_tags,tst_tags"
" WHERE tst_questions.CrsCod=%ld"
" AND tst_questions.QstCod NOT IN"
" (SELECT tst_question_tags.QstCod"
" FROM tst_tags,tst_question_tags"
" WHERE tst_tags.CrsCod=%ld"
" AND tst_tags.TagHidden='Y'"
" AND tst_tags.TagCod=tst_question_tags.TagCod)"
" AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod"
" AND tst_tags.CrsCod=%ld",
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Hierarchy.Crs.CrsCod);
if (!Questions->Tags.All) // User has not selected all the tags
{
/* Add selected tags */
LengthQuery = strlen (Query);
NumItemInList = 0;
Ptr = Questions->Tags.List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tag_MAX_BYTES_TAG);
LengthQuery = LengthQuery + 35 + strlen (TagText) + 1;
if (LengthQuery > Tst_MAX_BYTES_QUERY_QUESTIONS - 128)
Err_QuerySizeExceededExit ();
Str_Concat (Query,
NumItemInList ? " OR tst_tags.TagTxt='" :
" AND (tst_tags.TagTxt='",
Tst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,TagText,Tst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,"'",Tst_MAX_BYTES_QUERY_QUESTIONS);
NumItemInList++;
}
Str_Concat (Query,")",Tst_MAX_BYTES_QUERY_QUESTIONS);
}
/* Add answer types selected */
if (!Questions->AnswerTypes.All)
{
LengthQuery = strlen (Query);
NumItemInList = 0;
Ptr = Questions->AnswerTypes.List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,UnsignedStr,Tag_MAX_BYTES_TAG);
AnswerType = Qst_ConvertFromUnsignedStrToAnsTyp (UnsignedStr);
LengthQuery = LengthQuery + 35 + strlen (Qst_DB_StrAnswerTypes[AnswerType]) + 1;
if (LengthQuery > Tst_MAX_BYTES_QUERY_QUESTIONS - 128)
Err_QuerySizeExceededExit ();
Str_Concat (Query,
NumItemInList ? " OR tst_questions.AnsType='" :
" AND (tst_questions.AnsType='",
Tst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,Qst_DB_StrAnswerTypes[AnswerType],Tst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,"'",Tst_MAX_BYTES_QUERY_QUESTIONS);
NumItemInList++;
}
Str_Concat (Query,")",Tst_MAX_BYTES_QUERY_QUESTIONS);
}
/* End query */
Str_Concat (Query," ORDER BY RAND() LIMIT ",Tst_MAX_BYTES_QUERY_QUESTIONS);
snprintf (StrNumQsts,sizeof (StrNumQsts),"%u",Questions->NumQsts);
Str_Concat (Query,StrNumQsts,Tst_MAX_BYTES_QUERY_QUESTIONS);
/*
if (Gbl.Usrs.Me.Roles.LoggedRole == Rol_SYS_ADM)
Lay_ShowAlert (Lay_INFO,Query);
*/
/* Make the query */
return (unsigned)
DB_QuerySELECT (mysql_res,"can not get questions",
"%s",
Query);
}
/*****************************************************************************/
/****************** Remove test configuration in a course ********************/
/*****************************************************************************/
void Tst_DB_RemoveTstConfig (long CrsCod)
{
DB_QueryDELETE ("can not remove configuration of tests of a course",
"DELETE FROM tst_config"
" WHERE CrsCod=%ld",
CrsCod);
}

View File

@ -54,4 +54,9 @@ void Tst_DB_UpdateLastAccTst (unsigned NumQsts);
unsigned Tst_DB_GetDateNextTstAllowed (MYSQL_RES **mysql_res); unsigned Tst_DB_GetDateNextTstAllowed (MYSQL_RES **mysql_res);
unsigned Tst_DB_GetNumPrintsGeneratedByMe (MYSQL_RES **mysql_res); unsigned Tst_DB_GetNumPrintsGeneratedByMe (MYSQL_RES **mysql_res);
unsigned Tst_DB_GetQuestionsForNewTest (MYSQL_RES **mysql_res,
const struct Qst_Questions *Questions);
void Tst_DB_RemoveTstConfig (long CrsCod);
#endif #endif

View File

@ -762,6 +762,28 @@ static void TstPrn_WriteQstAndAnsExam (struct UsrData *UsrDat,
HTM_TR_End (); HTM_TR_End ();
} }
/*****************************************************************************/
/******** Get questions and answers from form to assess a test print *********/
/*****************************************************************************/
void TstPrn_GetAnswersFromForm (struct TstPrn_Print *Print)
{
unsigned QstInd;
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
/***** Loop for every question getting user's answers *****/
for (QstInd = 0;
QstInd < Print->NumQsts.All;
QstInd++)
{
/* Get answers selected by user for this question */
snprintf (StrAns,sizeof (StrAns),"Ans%010u",QstInd);
Par_GetParMultiToText (StrAns,Print->PrintedQuestions[QstInd].StrAnswers,
Qst_MAX_BYTES_ANSWERS_ONE_QST); /* If answer type == T/F ==> " ", "T", "F"; if choice ==> "0", "2",... */
Par_ReplaceSeparatorMultipleByComma (Print->PrintedQuestions[QstInd].StrAnswers);
}
}
/*****************************************************************************/ /*****************************************************************************/
/*********** Compute score of each question and store in database ************/ /*********** Compute score of each question and store in database ************/
/*****************************************************************************/ /*****************************************************************************/
@ -1956,7 +1978,7 @@ void TstPrn_ShowMyPrints (void)
TstPrn_ShowHeaderPrints (Usr_ME); TstPrn_ShowHeaderPrints (Usr_ME);
/***** List my tests *****/ /***** List my tests *****/
TstCfg_GetConfigFromDB (); // To get visibility TstCfg_GetConfig (); // To get visibility
TstPrn_ShowUsrPrints (&Gbl.Usrs.Me.UsrDat); TstPrn_ShowUsrPrints (&Gbl.Usrs.Me.UsrDat);
/***** End table and box *****/ /***** End table and box *****/
@ -2435,7 +2457,7 @@ void TstPrn_ShowOnePrint (void)
/***** Get if I can see print result and score *****/ /***** Get if I can see print result and score *****/
if (Gbl.Usrs.Me.Role.Logged == Rol_STD) if (Gbl.Usrs.Me.Role.Logged == Rol_STD)
TstCfg_GetConfigFromDB (); // To get visibility TstCfg_GetConfig (); // To get visibility
TstRes_CheckIfICanSeePrintResult (&Print,Gbl.Usrs.Other.UsrDat.UsrCod,&ICanView); TstRes_CheckIfICanSeePrintResult (&Print,Gbl.Usrs.Other.UsrDat.UsrCod,&ICanView);
if (ICanView.Result) // I am allowed to view this test print result if (ICanView.Result) // I am allowed to view this test print result

View File

@ -100,6 +100,8 @@ void TstPrn_ShowTestPrintToFillIt (struct TstPrn_Print *Print,
void TstPrn_ShowPrintAfterAssess (struct TstPrn_Print *Print); void TstPrn_ShowPrintAfterAssess (struct TstPrn_Print *Print);
void TstPrn_GetAnswersFromForm (struct TstPrn_Print *Print);
void TstPrn_ComputeScoresAndStoreQuestionsOfPrint (struct TstPrn_Print *Print, void TstPrn_ComputeScoresAndStoreQuestionsOfPrint (struct TstPrn_Print *Print,
bool UpdateQstScore); bool UpdateQstScore);
void TstPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion, void TstPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion,