Version 21.44: Oct 25, 2021 Functions moved to module swad_question.

This commit is contained in:
acanas 2021-10-25 13:52:17 +02:00
parent b1854d0dea
commit 3bfa2807fe
12 changed files with 684 additions and 667 deletions

View File

@ -4240,7 +4240,7 @@ static int API_GetTstQuestions (struct soap *soap,
long CrsCod,long BeginTime, long CrsCod,long BeginTime,
struct swad__getTestsOutput *getTestsOut) struct swad__getTestsOutput *getTestsOut)
{ {
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES]; extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
unsigned NumRow; unsigned NumRow;
@ -4305,7 +4305,7 @@ static int API_GetTstQuestions (struct soap *soap,
getTestsOut->questionsArray.__ptr[NumRow].answerType = getTestsOut->questionsArray.__ptr[NumRow].answerType =
soap_malloc (soap,Qst_MAX_BYTES_ANSWER_TYPE + 1); soap_malloc (soap,Qst_MAX_BYTES_ANSWER_TYPE + 1);
Str_Copy (getTestsOut->questionsArray.__ptr[NumRow].answerType, Str_Copy (getTestsOut->questionsArray.__ptr[NumRow].answerType,
Tst_StrAnswerTypesXML[AnswerType], Qst_StrAnswerTypesXML[AnswerType],
Qst_MAX_BYTES_ANSWER_TYPE); Qst_MAX_BYTES_ANSWER_TYPE);
/* Get shuffle (row[2]) */ /* Get shuffle (row[2]) */
@ -4340,7 +4340,7 @@ static int API_GetTstAnswers (struct soap *soap,
long CrsCod,long BeginTime, long CrsCod,long BeginTime,
struct swad__getTestsOutput *getTestsOut) struct swad__getTestsOutput *getTestsOut)
{ {
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES]; extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
unsigned NumRow,NumRows; unsigned NumRow,NumRows;
@ -4440,7 +4440,7 @@ static int API_GetTstQuestionTags (struct soap *soap,
long CrsCod,long BeginTime, long CrsCod,long BeginTime,
struct swad__getTestsOutput *getTestsOut) struct swad__getTestsOutput *getTestsOut)
{ {
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES]; extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
unsigned NumRow,NumRows; unsigned NumRow,NumRows;
@ -4527,7 +4527,7 @@ int swad__getTrivialQuestion (struct soap *soap,
char *wsKey,char *degrees,float lowerScore,float upperScore, // input char *wsKey,char *degrees,float lowerScore,float upperScore, // input
struct swad__getTrivialQuestionOutput *getTrivialQuestionOut) // output struct swad__getTrivialQuestionOutput *getTrivialQuestionOut) // output
{ {
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES]; extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
int ReturnCode; int ReturnCode;
const char *Ptr; const char *Ptr;
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1]; char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
@ -4653,7 +4653,7 @@ int swad__getTrivialQuestion (struct soap *soap,
getTrivialQuestionOut->question.answerType = getTrivialQuestionOut->question.answerType =
soap_malloc (soap,Qst_MAX_BYTES_ANSWER_TYPE + 1); soap_malloc (soap,Qst_MAX_BYTES_ANSWER_TYPE + 1);
Str_Copy (getTrivialQuestionOut->question.answerType, Str_Copy (getTrivialQuestionOut->question.answerType,
Tst_StrAnswerTypesXML[AnswerType],Qst_MAX_BYTES_ANSWER_TYPE); Qst_StrAnswerTypesXML[AnswerType],Qst_MAX_BYTES_ANSWER_TYPE);
/* Get shuffle (row[2]) */ /* Get shuffle (row[2]) */
getTrivialQuestionOut->question.shuffle = (row[2][0] == 'Y') ? 1 : getTrivialQuestionOut->question.shuffle = (row[2][0] == 'Y') ? 1 :

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.43 (2021-10-25)" #define Log_PLATFORM_VERSION "SWAD 21.44 (2021-10-25)"
#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.44: Oct 25, 2021 Functions moved to module swad_question. (320928 lines)
Version 21.43: Oct 25, 2021 New module swad_question for test/exam/game questions. (320919 lines) Version 21.43: Oct 25, 2021 New module swad_question for test/exam/game questions. (320919 lines)
Version 21.42.2: Oct 25, 2021 Code refactoring in test questions. (320795 lines) Version 21.42.2: Oct 25, 2021 Code refactoring in test questions. (320795 lines)
Version 21.42.1: Oct 25, 2021 Code refactoring in test questions. (320784 lines) Version 21.42.1: Oct 25, 2021 Code refactoring in test questions. (320784 lines)

View File

@ -861,7 +861,7 @@ void Exa_DB_RemoveAllSetsFromCrs (long CrsCod)
long Exa_DB_AddQuestionToSet (long SetCod,const struct Qst_Question *Question,long MedCod) long Exa_DB_AddQuestionToSet (long SetCod,const struct Qst_Question *Question,long MedCod)
{ {
extern const char *Tst_StrAnswerTypesDB[Qst_NUM_ANS_TYPES]; extern const char *Qst_DB_StrAnswerTypes[Qst_NUM_ANS_TYPES];
static char CharInvalid[Qst_NUM_VALIDITIES] = static char CharInvalid[Qst_NUM_VALIDITIES] =
{ {
[Qst_INVALID_QUESTION] = 'Y', [Qst_INVALID_QUESTION] = 'Y',
@ -878,7 +878,7 @@ long Exa_DB_AddQuestionToSet (long SetCod,const struct Qst_Question *Question,lo
"'%s','%s',%ld)", "'%s','%s',%ld)",
SetCod, SetCod,
CharInvalid[Question->Validity], CharInvalid[Question->Validity],
Tst_StrAnswerTypesDB[Question->Answer.Type], Qst_DB_StrAnswerTypes[Question->Answer.Type],
Question->Answer.Shuffle ? 'Y' : Question->Answer.Shuffle ? 'Y' :
'N', 'N',
Question->Stem, Question->Stem,

View File

@ -33,18 +33,18 @@
// #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"
// #include "swad_global.h" #include "swad_global.h"
// #include "swad_hierarchy_level.h" // #include "swad_hierarchy_level.h"
// #include "swad_HTML.h" // #include "swad_HTML.h"
// #include "swad_ID.h" // #include "swad_ID.h"
@ -53,9 +53,9 @@
// #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"
@ -67,6 +67,27 @@
/***************************** Public constants ******************************/ /***************************** Public constants ******************************/
/*****************************************************************************/ /*****************************************************************************/
// strings are limited to Qst_MAX_BYTES_ANSWER_TYPE characters
const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES] =
{
[Qst_ANS_INT ] = "int",
[Qst_ANS_FLOAT ] = "float",
[Qst_ANS_TRUE_FALSE ] = "TF",
[Qst_ANS_UNIQUE_CHOICE ] = "uniqueChoice",
[Qst_ANS_MULTIPLE_CHOICE] = "multipleChoice",
[Qst_ANS_TEXT ] = "text",
};
const char *Qst_DB_StrAnswerTypes[Qst_NUM_ANS_TYPES] =
{
[Qst_ANS_INT ] = "int",
[Qst_ANS_FLOAT ] = "float",
[Qst_ANS_TRUE_FALSE ] = "true_false",
[Qst_ANS_UNIQUE_CHOICE ] = "unique_choice",
[Qst_ANS_MULTIPLE_CHOICE] = "multiple_choice",
[Qst_ANS_TEXT ] = "text",
};
/*****************************************************************************/ /*****************************************************************************/
/**************************** Private constants ******************************/ /**************************** Private constants ******************************/
/*****************************************************************************/ /*****************************************************************************/
@ -89,6 +110,250 @@ extern struct Globals Gbl;
/***************************** Private prototypes ****************************/ /***************************** Private prototypes ****************************/
/*****************************************************************************/ /*****************************************************************************/
/*****************************************************************************/
/***************** List several test questions for edition *******************/
/*****************************************************************************/
void Qst_ListQuestionsToEdit (void)
{
struct Qst_Questions Questions;
MYSQL_RES *mysql_res;
/***** Create test *****/
Qst_Constructor (&Questions);
/***** Get parameters, query the database and list the questions *****/
if (Tst_GetParamsTst (&Questions,Tst_EDIT_QUESTIONS)) // Get parameters from the form
{
/***** Get question codes from database *****/
Qst_GetQuestions (&Questions,&mysql_res); // Query database
if (Questions.NumQsts)
{
/* Contextual menu */
if (QstImp_GetCreateXMLParamFromForm ())
{
Mnu_ContextMenuBegin ();
QstImp_CreateXML (Questions.NumQsts,mysql_res); // Create XML file with exported questions...
// ...and put a link to download it
Mnu_ContextMenuEnd ();
}
/* Show the table with the questions */
Qst_ListOneOrMoreQstsForEdition (&Questions,mysql_res);
}
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
else
/* Show the form again */
Qst_ShowFormRequestEditQsts (&Questions);
/***** Destroy test *****/
Qst_Destructor (&Questions);
}
/*****************************************************************************/
/************ List several test questions for selection for exam *************/
/*****************************************************************************/
void Qst_ListQuestionsToSelectForExamSet (struct Exa_Exams *Exams)
{
struct Qst_Questions Questions;
MYSQL_RES *mysql_res;
/***** Create test *****/
Qst_Constructor (&Questions);
/***** Get parameters, query the database and list the questions *****/
if (Tst_GetParamsTst (&Questions,Tst_SELECT_QUESTIONS_FOR_EXAM)) // Get parameters from the form
{
Qst_GetQuestions (&Questions,&mysql_res); // Query database
if (Questions.NumQsts)
/* Show the table with the questions */
Qst_ListOneOrMoreQstsForSelectionForExamSet (Exams,Questions.NumQsts,mysql_res);
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
else
/* Show the form again */
Qst_ShowFormRequestSelectQstsForExamSet (Exams,&Questions);
/***** Destroy test *****/
Qst_Destructor (&Questions);
}
/*****************************************************************************/
/************ List several test questions for selection for game *************/
/*****************************************************************************/
void Qst_ListQuestionsToSelectForGame (struct Gam_Games *Games)
{
struct Qst_Questions Questions;
MYSQL_RES *mysql_res;
/***** Create test *****/
Qst_Constructor (&Questions);
/***** Get parameters, query the database and list the questions *****/
if (Tst_GetParamsTst (&Questions,Tst_SELECT_QUESTIONS_FOR_GAME)) // Get parameters from the form
{
Qst_GetQuestions (&Questions,&mysql_res); // Query database
if (Questions.NumQsts)
/* Show the table with the questions */
Qst_ListOneOrMoreQstsForSelectionForGame (Games,Questions.NumQsts,mysql_res);
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
else
/* Show the form again */
Qst_ShowFormRequestSelectQstsForGame (Games,&Questions);
/***** Destroy test *****/
Qst_Destructor (&Questions);
}
/*****************************************************************************/
/********** Get from the database several test questions for listing *********/
/*****************************************************************************/
#define Qst_MAX_BYTES_QUERY_QUESTIONS (16 * 1024 - 1)
void Qst_GetQuestions (struct Qst_Questions *Questions,MYSQL_RES **mysql_res)
{
extern const char *Txt_No_questions_found_matching_your_search_criteria;
char *Query = NULL;
long LengthQuery;
unsigned NumItemInList;
const char *Ptr;
char TagText[Tag_MAX_BYTES_TAG + 1];
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
char UnsignedStr[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
Qst_AnswerType_t AnsType;
char CrsCodStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
/***** Allocate space for query *****/
if ((Query = malloc (Qst_MAX_BYTES_QUERY_QUESTIONS + 1)) == NULL)
Err_NotEnoughMemoryExit ();
/***** Select questions *****/
/* Begin query */
Str_Copy (Query,"SELECT tst_questions.QstCod" // row[0]
" FROM tst_questions",Qst_MAX_BYTES_QUERY_QUESTIONS);
if (!Questions->Tags.All)
Str_Concat (Query,",tst_question_tags,tst_tags",Qst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query," WHERE tst_questions.CrsCod='",Qst_MAX_BYTES_QUERY_QUESTIONS);
snprintf (CrsCodStr,sizeof (CrsCodStr),"%ld",Gbl.Hierarchy.Crs.CrsCod);
Str_Concat (Query,CrsCodStr,Qst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,"' AND tst_questions.EditTime>=FROM_UNIXTIME('",
Qst_MAX_BYTES_QUERY_QUESTIONS);
snprintf (LongStr,sizeof (LongStr),"%ld",
(long) Gbl.DateRange.TimeUTC[Dat_STR_TIME]);
Str_Concat (Query,LongStr,Qst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,"') AND tst_questions.EditTime<=FROM_UNIXTIME('",
Qst_MAX_BYTES_QUERY_QUESTIONS);
snprintf (LongStr,sizeof (LongStr),"%ld",
(long) Gbl.DateRange.TimeUTC[Dat_END_TIME]);
Str_Concat (Query,LongStr,Qst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,"')",Qst_MAX_BYTES_QUERY_QUESTIONS);
/* Add the tags selected */
if (!Questions->Tags.All)
{
Str_Concat (Query," AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod"
" AND tst_tags.CrsCod='",
Qst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,CrsCodStr,Qst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,"'",Qst_MAX_BYTES_QUERY_QUESTIONS);
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 > Qst_MAX_BYTES_QUERY_QUESTIONS - 256)
Err_ShowErrorAndExit ("Query size exceed.");
Str_Concat (Query,
NumItemInList ? " OR tst_tags.TagTxt='" :
" AND (tst_tags.TagTxt='",
Qst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,TagText,Qst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,"'",Qst_MAX_BYTES_QUERY_QUESTIONS);
NumItemInList++;
}
Str_Concat (Query,")",Qst_MAX_BYTES_QUERY_QUESTIONS);
}
/* Add the types of answer selected */
if (!Questions->AnswerTypes.All)
{
LengthQuery = strlen (Query);
NumItemInList = 0;
Ptr = Questions->AnswerTypes.List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,UnsignedStr,Tag_MAX_BYTES_TAG);
AnsType = Qst_ConvertFromUnsignedStrToAnsTyp (UnsignedStr);
LengthQuery = LengthQuery + 35 + strlen (Qst_DB_StrAnswerTypes[AnsType]) + 1;
if (LengthQuery > Qst_MAX_BYTES_QUERY_QUESTIONS - 256)
Err_ShowErrorAndExit ("Query size exceed.");
Str_Concat (Query,
NumItemInList ? " OR tst_questions.AnsType='" :
" AND (tst_questions.AnsType='",
Qst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,Qst_DB_StrAnswerTypes[AnsType],Qst_MAX_BYTES_QUERY_QUESTIONS);
Str_Concat (Query,"'",Qst_MAX_BYTES_QUERY_QUESTIONS);
NumItemInList++;
}
Str_Concat (Query,")",Qst_MAX_BYTES_QUERY_QUESTIONS);
}
/* End the query */
Str_Concat (Query," GROUP BY tst_questions.QstCod",Qst_MAX_BYTES_QUERY_QUESTIONS);
switch (Questions->SelectedOrder)
{
case Qst_ORDER_STEM:
Str_Concat (Query," ORDER BY tst_questions.Stem",
Qst_MAX_BYTES_QUERY_QUESTIONS);
break;
case Qst_ORDER_NUM_HITS:
Str_Concat (Query," ORDER BY tst_questions.NumHits DESC,"
"tst_questions.Stem",
Qst_MAX_BYTES_QUERY_QUESTIONS);
break;
case Qst_ORDER_AVERAGE_SCORE:
Str_Concat (Query," ORDER BY tst_questions.Score/tst_questions.NumHits DESC,"
"tst_questions.NumHits DESC,"
"tst_questions.Stem",
Qst_MAX_BYTES_QUERY_QUESTIONS);
break;
case Qst_ORDER_NUM_HITS_NOT_BLANK:
Str_Concat (Query," ORDER BY tst_questions.NumHitsNotBlank DESC,"
"tst_questions.Stem",
Qst_MAX_BYTES_QUERY_QUESTIONS);
break;
case Qst_ORDER_AVERAGE_SCORE_NOT_BLANK:
Str_Concat (Query," ORDER BY tst_questions.Score/tst_questions.NumHitsNotBlank DESC,"
"tst_questions.NumHitsNotBlank DESC,"
"tst_questions.Stem",
Qst_MAX_BYTES_QUERY_QUESTIONS);
break;
}
/* Make the query */
Questions->NumQsts = (unsigned) DB_QuerySELECT (mysql_res,"can not get questions",
"%s",
Query);
if (Questions->NumQsts == 0)
Ale_ShowAlert (Ale_INFO,Txt_No_questions_found_matching_your_search_criteria);
}
/*****************************************************************************/ /*****************************************************************************/
/***************** Change format of answers text / feedback ******************/ /***************** Change format of answers text / feedback ******************/
/*****************************************************************************/ /*****************************************************************************/
@ -123,3 +388,37 @@ void Qst_ChangeFormatAnswersFeedback (struct Qst_Question *Question)
Question->Answer.Options[NumOpt].Feedback, Question->Answer.Options[NumOpt].Feedback,
Qst_MAX_BYTES_ANSWER_OR_FEEDBACK,false); Qst_MAX_BYTES_ANSWER_OR_FEEDBACK,false);
} }
/*****************************************************************************/
/** Convert a string with the type of answer in database to type of answer ***/
/*****************************************************************************/
Qst_AnswerType_t Qst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeDB)
{
Qst_AnswerType_t AnsType;
if (StrAnsTypeDB != NULL)
if (StrAnsTypeDB[0])
for (AnsType = (Qst_AnswerType_t) 0;
AnsType <= (Qst_AnswerType_t) (Qst_NUM_ANS_TYPES - 1);
AnsType++)
if (!strcmp (StrAnsTypeDB,Qst_DB_StrAnswerTypes[AnsType]))
return AnsType;
return Qst_ANS_UNKNOWN;
}
/*****************************************************************************/
/************ Convert a string with an unsigned to answer type ***************/
/*****************************************************************************/
Qst_AnswerType_t Qst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr)
{
unsigned AnsType;
if (sscanf (UnsignedStr,"%u",&AnsType) != 1)
Err_WrongAnswerExit ();
if (AnsType >= Qst_NUM_ANS_TYPES)
Err_WrongAnswerExit ();
return (Qst_AnswerType_t) AnsType;
}

View File

@ -30,10 +30,13 @@
#include <stdbool.h> // For boolean type #include <stdbool.h> // For boolean type
#include <time.h> // For time_t #include <time.h> // For time_t
// #include "swad_question_type.h" #include "swad_exam.h"
#include "swad_game.h"
#include "swad_question_type.h"
#include "swad_media.h" #include "swad_media.h"
#include "swad_string.h" #include "swad_string.h"
#include "swad_tag.h" #include "swad_tag.h"
// #include "swad_test.h"
// #include "swad_test_config.h" // #include "swad_test_config.h"
// #include "swad_test_visibility.h" // #include "swad_test_visibility.h"
// #include "swad_user.h" // #include "swad_user.h"
@ -42,24 +45,30 @@
/***************************** Public constants ******************************/ /***************************** Public constants ******************************/
/*****************************************************************************/ /*****************************************************************************/
#define Qst_MAX_BYTES_ANSWER_TYPE 32
#define Qst_MAX_BYTES_FLOAT_ANSWER 30 // Maximum length of the strings that store an floating point answer
#define Qst_MAX_OPTIONS_PER_QUESTION 10
#define Qst_MAX_BYTES_INDEXES_ONE_QST (Qst_MAX_OPTIONS_PER_QUESTION * (3 + 1))
#define Qst_MAX_CHARS_ANSWER_OR_FEEDBACK (1024 - 1) // 1023 #define Qst_MAX_CHARS_ANSWER_OR_FEEDBACK (1024 - 1) // 1023
#define Qst_MAX_BYTES_ANSWER_OR_FEEDBACK ((Qst_MAX_CHARS_ANSWER_OR_FEEDBACK + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 16383 #define Qst_MAX_BYTES_ANSWER_OR_FEEDBACK ((Qst_MAX_CHARS_ANSWER_OR_FEEDBACK + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 16383
#define Qst_MAX_CHARS_ANSWERS_ONE_QST (128 - 1) // 127
#define Qst_MAX_BYTES_ANSWERS_ONE_QST ((Qst_MAX_CHARS_ANSWERS_ONE_QST + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047
/*****************************************************************************/ /*****************************************************************************/
/******************************* Public types ********************************/ /******************************* Public types ********************************/
/*****************************************************************************/ /*****************************************************************************/
struct Qst_AnswerTypes
{
bool All;
char List[Qst_MAX_BYTES_LIST_ANSWER_TYPES + 1];
};
#define Qst_NUM_TYPES_ORDER_QST 5
typedef enum
{
Qst_ORDER_STEM = 0,
Qst_ORDER_NUM_HITS = 1,
Qst_ORDER_AVERAGE_SCORE = 2,
Qst_ORDER_NUM_HITS_NOT_BLANK = 3,
Qst_ORDER_AVERAGE_SCORE_NOT_BLANK = 4,
} Qst_QuestionsOrder_t;
#define Qst_DEFAULT_ORDER Qst_ORDER_STEM
#define Qst_NUM_VALIDITIES 2 #define Qst_NUM_VALIDITIES 2
typedef enum typedef enum
{ {
@ -67,19 +76,6 @@ typedef enum
Qst_VALID_QUESTION, Qst_VALID_QUESTION,
} Qst_Validity_t; } Qst_Validity_t;
#define Qst_NUM_ANS_TYPES 6
#define Qst_MAX_BYTES_LIST_ANSWER_TYPES (Qst_NUM_ANS_TYPES * (Cns_MAX_DECIMAL_DIGITS_UINT + 1))
typedef enum
{
Qst_ANS_INT = 0,
Qst_ANS_FLOAT = 1,
Qst_ANS_TRUE_FALSE = 2,
Qst_ANS_UNIQUE_CHOICE = 3,
Qst_ANS_MULTIPLE_CHOICE = 4,
Qst_ANS_TEXT = 5,
Qst_ANS_UNKNOWN = 6, // Unknown/all/any type of answer
} Qst_AnswerType_t;
struct Qst_Question struct Qst_Question
{ {
long QstCod; long QstCod;
@ -110,11 +106,29 @@ struct Qst_Question
Qst_Validity_t Validity; // If a question in an exam has been marked as invalid Qst_Validity_t Validity; // If a question in an exam has been marked as invalid
}; };
struct Qst_Questions
{
struct Tag_Tags Tags; // Selected tags
struct Qst_AnswerTypes AnswerTypes; // Selected answer types
Qst_QuestionsOrder_t SelectedOrder; // Order for listing questions
unsigned NumQsts; // Number of questions
struct Qst_Question Question; // Selected / editing question
};
/*****************************************************************************/ /*****************************************************************************/
/***************************** Public prototypes *****************************/ /***************************** Public prototypes *****************************/
/*****************************************************************************/ /*****************************************************************************/
void Qst_ListQuestionsToEdit (void);
void Qst_ListQuestionsToSelectForExamSet (struct Exa_Exams *Exams);
void Qst_ListQuestionsToSelectForGame (struct Gam_Games *Games);
void Qst_GetQuestions (struct Qst_Questions *Questions,MYSQL_RES **mysql_res);
void Qst_ChangeFormatAnswersText (struct Qst_Question *Question); void Qst_ChangeFormatAnswersText (struct Qst_Question *Question);
void Qst_ChangeFormatAnswersFeedback (struct Qst_Question *Question); void Qst_ChangeFormatAnswersFeedback (struct Qst_Question *Question);
Qst_AnswerType_t Qst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeDB);
Qst_AnswerType_t Qst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr);
#endif #endif

View File

@ -67,7 +67,7 @@ extern struct Globals Gbl;
/***************************** Private prototypes ****************************/ /***************************** Private prototypes ****************************/
/*****************************************************************************/ /*****************************************************************************/
static void QstImp_PutParamsExportQsts (void *Test); static void QstImp_PutParamsExportQsts (void *Questions);
static void QstImp_PutCreateXMLParam (void); static void QstImp_PutCreateXMLParam (void);
static void QstImp_ExportQuestion (struct Qst_Question *Question,FILE *FileXML); static void QstImp_ExportQuestion (struct Qst_Question *Question,FILE *FileXML);
@ -90,13 +90,13 @@ static void QstImp_WriteRowImportedQst (struct XMLElement *StemElem,
/**************** Put a link (form) to export test questions *****************/ /**************** Put a link (form) to export test questions *****************/
/*****************************************************************************/ /*****************************************************************************/
void QstImp_PutIconToExportQuestions (struct Tst_Test *Test) void QstImp_PutIconToExportQuestions (struct Qst_Questions *Questions)
{ {
extern const char *Txt_Export_questions; extern const char *Txt_Export_questions;
/***** Put a link to create a file with questions *****/ /***** Put a link to create a file with questions *****/
Lay_PutContextualLinkOnlyIcon (ActLstTstQst,NULL, Lay_PutContextualLinkOnlyIcon (ActLstTstQst,NULL,
QstImp_PutParamsExportQsts,Test, QstImp_PutParamsExportQsts,Questions,
"file-import.svg", "file-import.svg",
Txt_Export_questions); Txt_Export_questions);
} }
@ -105,13 +105,13 @@ void QstImp_PutIconToExportQuestions (struct Tst_Test *Test)
/****************** Put params to export test questions **********************/ /****************** Put params to export test questions **********************/
/*****************************************************************************/ /*****************************************************************************/
static void QstImp_PutParamsExportQsts (void *Test) static void QstImp_PutParamsExportQsts (void *Questions)
{ {
if (Test) if (Questions)
{ {
Qst_PutParamsEditQst (Test); Qst_PutParamsEditQst (Questions);
Par_PutHiddenParamChar ("OnlyThisQst",'N'); Par_PutHiddenParamChar ("OnlyThisQst",'N');
Par_PutHiddenParamUnsigned (NULL,"Order",(unsigned) (((struct Tst_Test *) Test)->SelectedOrder)); Par_PutHiddenParamUnsigned (NULL,"Order",(unsigned) (((struct Qst_Questions *) Questions)->SelectedOrder));
QstImp_PutCreateXMLParam (); QstImp_PutCreateXMLParam ();
} }
} }
@ -255,14 +255,14 @@ void QstImp_CreateXML (unsigned NumQsts,MYSQL_RES *mysql_res)
static void QstImp_ExportQuestion (struct Qst_Question *Question,FILE *FileXML) static void QstImp_ExportQuestion (struct Qst_Question *Question,FILE *FileXML)
{ {
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES]; extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
extern const char *Txt_NEW_LINE; extern const char *Txt_NEW_LINE;
if (Qst_GetQstDataFromDB (Question)) if (Qst_GetQstDataFromDB (Question))
{ {
/***** Write the answer type *****/ /***** Write the answer type *****/
fprintf (FileXML,"<question type=\"%s\">%s", fprintf (FileXML,"<question type=\"%s\">%s",
Tst_StrAnswerTypesXML[Question->Answer.Type],Txt_NEW_LINE); Qst_StrAnswerTypesXML[Question->Answer.Type],Txt_NEW_LINE);
/***** Write the question tags *****/ /***** Write the question tags *****/
fprintf (FileXML,"<tags>%s",Txt_NEW_LINE); fprintf (FileXML,"<tags>%s",Txt_NEW_LINE);
@ -680,7 +680,7 @@ static void QstImp_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
static Qst_AnswerType_t QstImp_ConvertFromStrAnsTypXMLToAnsTyp (const char *StrAnsTypeXML) static Qst_AnswerType_t QstImp_ConvertFromStrAnsTypXMLToAnsTyp (const char *StrAnsTypeXML)
{ {
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES]; extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
Qst_AnswerType_t AnsType; Qst_AnswerType_t AnsType;
if (StrAnsTypeXML != NULL) if (StrAnsTypeXML != NULL)
@ -688,7 +688,7 @@ static Qst_AnswerType_t QstImp_ConvertFromStrAnsTypXMLToAnsTyp (const char *StrA
AnsType <= (Qst_AnswerType_t) (Qst_NUM_ANS_TYPES - 1); AnsType <= (Qst_AnswerType_t) (Qst_NUM_ANS_TYPES - 1);
AnsType++) AnsType++)
// comparison must be case insensitive, because users can edit XML // comparison must be case insensitive, because users can edit XML
if (!strcasecmp (StrAnsTypeXML,Tst_StrAnswerTypesXML[AnsType])) if (!strcasecmp (StrAnsTypeXML,Qst_StrAnswerTypesXML[AnsType]))
return AnsType; return AnsType;
Err_WrongAnswerExit (); Err_WrongAnswerExit ();

View File

@ -27,6 +27,8 @@
/********************************* Headers ***********************************/ /********************************* Headers ***********************************/
/*****************************************************************************/ /*****************************************************************************/
#include "swad_test.h"
/*****************************************************************************/ /*****************************************************************************/
/***************************** Public constants ******************************/ /***************************** Public constants ******************************/
/*****************************************************************************/ /*****************************************************************************/
@ -39,7 +41,7 @@
/***************************** Public prototypes *****************************/ /***************************** Public prototypes *****************************/
/*****************************************************************************/ /*****************************************************************************/
void QstImp_PutIconToExportQuestions (struct Tst_Test *Test); void QstImp_PutIconToExportQuestions (struct Qst_Questions *Questions);
bool QstImp_GetCreateXMLParamFromForm (void); bool QstImp_GetCreateXMLParamFromForm (void);
void QstImp_PutIconToImportQuestions (void); void QstImp_PutIconToImportQuestions (void);
void QstImp_CreateXML (unsigned long NumRows,MYSQL_RES *mysql_res); void QstImp_CreateXML (unsigned long NumRows,MYSQL_RES *mysql_res);

View File

@ -31,12 +31,33 @@
#include "swad_tag.h" #include "swad_tag.h"
/*****************************************************************************/ /*****************************************************************************/
/***************************** Public constants ******************************/ /************************* Public constants and types ************************/
/*****************************************************************************/ /*****************************************************************************/
/*****************************************************************************/ #define Qst_NUM_ANS_TYPES 6
/******************************* Public types ********************************/ #define Qst_MAX_BYTES_LIST_ANSWER_TYPES (Qst_NUM_ANS_TYPES * (Cns_MAX_DECIMAL_DIGITS_UINT + 1))
/*****************************************************************************/ typedef enum
{
Qst_ANS_INT = 0,
Qst_ANS_FLOAT = 1,
Qst_ANS_TRUE_FALSE = 2,
Qst_ANS_UNIQUE_CHOICE = 3,
Qst_ANS_MULTIPLE_CHOICE = 4,
Qst_ANS_TEXT = 5,
Qst_ANS_UNKNOWN = 6, // Unknown/all/any type of answer
} Qst_AnswerType_t;
#define Qst_MAX_BYTES_ANSWER_TYPE 32
#define Qst_MAX_BYTES_FLOAT_ANSWER 30 // Maximum length of the strings that store an floating point answer
#define Qst_MAX_OPTIONS_PER_QUESTION 10
#define Qst_MAX_BYTES_INDEXES_ONE_QST (Qst_MAX_OPTIONS_PER_QUESTION * (3 + 1))
#define Qst_MAX_CHARS_ANSWERS_ONE_QST (128 - 1) // 127
#define Qst_MAX_BYTES_ANSWERS_ONE_QST ((Qst_MAX_CHARS_ANSWERS_ONE_QST + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047
/*****************************************************************************/ /*****************************************************************************/
/***************************** Public prototypes *****************************/ /***************************** Public prototypes *****************************/

File diff suppressed because it is too large Load Diff

View File

@ -45,32 +45,6 @@
/******************************* Public types ********************************/ /******************************* Public types ********************************/
/*****************************************************************************/ /*****************************************************************************/
struct Qst_AnswerTypes
{
bool All;
char List[Qst_MAX_BYTES_LIST_ANSWER_TYPES + 1];
};
#define Qst_NUM_TYPES_ORDER_QST 5
typedef enum
{
Qst_ORDER_STEM = 0,
Qst_ORDER_NUM_HITS = 1,
Qst_ORDER_AVERAGE_SCORE = 2,
Qst_ORDER_NUM_HITS_NOT_BLANK = 3,
Qst_ORDER_AVERAGE_SCORE_NOT_BLANK = 4,
} Qst_QuestionsOrder_t;
#define Qst_DEFAULT_ORDER Qst_ORDER_STEM
struct Tst_Test
{
struct Tag_Tags Tags; // Selected tags
struct Qst_AnswerTypes AnswerTypes; // Selected answer types
Qst_QuestionsOrder_t SelectedOrder; // Order for listing questions
unsigned NumQsts; // Number of questions
struct Qst_Question Question; // Selected / editing question
};
typedef enum typedef enum
{ {
Tst_SHOW_TEST_TO_ANSWER, // Showing a test to a student Tst_SHOW_TEST_TO_ANSWER, // Showing a test to a student
@ -98,6 +72,10 @@ struct Tst_Stats
/*****************************************************************************/ /*****************************************************************************/
void Tst_RequestTest (void); void Tst_RequestTest (void);
void Qst_Constructor (struct Qst_Questions *Questions);
void Qst_Destructor (struct Qst_Questions *Questions);
void Tst_ShowNewTest (void); void Tst_ShowNewTest (void);
void Tst_ReceiveTestDraft (void); void Tst_ReceiveTestDraft (void);
void Tst_AssessTest (void); void Tst_AssessTest (void);
@ -111,14 +89,24 @@ void Qst_WriteQstStem (const char *Stem,const char *ClassStem,bool Visible);
void Qst_WriteQstFeedback (const char *Feedback,const char *ClassFeedback); void Qst_WriteQstFeedback (const char *Feedback,const char *ClassFeedback);
void Qst_RequestEditQsts (void); void Qst_RequestEditQsts (void);
void Qst_ShowFormRequestEditQsts (struct Qst_Questions *Questions);
void Qst_RequestSelectQstsForExamSet (struct Exa_Exams *Exams); void Qst_RequestSelectQstsForExamSet (struct Exa_Exams *Exams);
void Qst_RequestSelectQstsForGame (struct Gam_Games *Games); void Qst_RequestSelectQstsForGame (struct Gam_Games *Games);
void Qst_ShowFormRequestSelectQstsForExamSet (struct Exa_Exams *Exams,
struct Qst_Questions *Questions);
void Qst_ShowFormRequestSelectQstsForGame (struct Gam_Games *Games,
struct Qst_Questions *Questions);
void Qst_ListQuestionsToEdit (void); void Qst_ListOneOrMoreQstsForEdition (struct Qst_Questions *Questions,
void Qst_ListQuestionsToSelectForExamSet (struct Exa_Exams *Exams); MYSQL_RES *mysql_res);
void Qst_ListQuestionsToSelectForGame (struct Gam_Games *Games); void Qst_ListOneOrMoreQstsForSelectionForExamSet (struct Exa_Exams *Exams,
unsigned NumQsts,
MYSQL_RES *mysql_res);
void Qst_ListOneOrMoreQstsForSelectionForGame (struct Gam_Games *Games,
unsigned NumQsts,
MYSQL_RES *mysql_res);
void Qst_PutParamsEditQst (void *Test); void Qst_PutParamsEditQst (void *Questions);
unsigned Qst_GetNumAnswersQst (long QstCod); unsigned Qst_GetNumAnswersQst (long QstCod);
void Qst_GetAnswersQst (struct Qst_Question *Question,MYSQL_RES **mysql_res, void Qst_GetAnswersQst (struct Qst_Question *Question,MYSQL_RES **mysql_res,
@ -133,6 +121,8 @@ void Qst_WriteParamQstCod (unsigned NumQst,long QstCod);
void Qst_CheckIfNumberOfAnswersIsOne (const struct Qst_Question *Question); void Qst_CheckIfNumberOfAnswersIsOne (const struct Qst_Question *Question);
bool Tst_GetParamsTst (struct Qst_Questions *Questions,
Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions);
void Tst_ShowFormConfig (void); void Tst_ShowFormConfig (void);
bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void); bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void);
@ -148,7 +138,6 @@ bool Qst_AllocateTextChoiceAnswer (struct Qst_Question *Question,unsigned NumOpt
Qst_AnswerType_t Qst_GetQstAnswerTypeFromDB (long QstCod); Qst_AnswerType_t Qst_GetQstAnswerTypeFromDB (long QstCod);
bool Qst_GetQstDataFromDB (struct Qst_Question *Question); bool Qst_GetQstDataFromDB (struct Qst_Question *Question);
Qst_AnswerType_t Qst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeDB);
void Qst_ReceiveQst (void); void Qst_ReceiveQst (void);
bool Qst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Qst_Question *Question); bool Qst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Qst_Question *Question);
@ -168,8 +157,6 @@ void Qst_PutParamQstCod (void *QstCod);
void Qst_InsertOrUpdateQstTagsAnsIntoDB (struct Qst_Question *Question); void Qst_InsertOrUpdateQstTagsAnsIntoDB (struct Qst_Question *Question);
void Qst_UpdateQstScoreInDB (struct TstPrn_PrintedQuestion *PrintedQuestion);
void Tst_RemoveCrsTests (long CrsCod); void Tst_RemoveCrsTests (long CrsCod);
void Qst_RemoveCrsQsts (long CrsCod); void Qst_RemoveCrsQsts (long CrsCod);

View File

@ -115,6 +115,8 @@ static void TstPrn_WriteQstAndAnsExam (struct UsrData *UsrDat,
bool QuestionExists, bool QuestionExists,
unsigned Visibility); unsigned Visibility);
static void TstPrn_UpdateQstScoreInDB (struct TstPrn_PrintedQuestion *PrintedQuestion);
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static void TstPrn_GetCorrectAndComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion, static void TstPrn_GetCorrectAndComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
struct Qst_Question *Question); struct Qst_Question *Question);
@ -634,7 +636,7 @@ void TstPrn_ShowPrintAfterAssess (struct TstPrn_Print *Print)
/***** Update the number of accesses and the score of this question *****/ /***** Update the number of accesses and the score of this question *****/
if (Gbl.Usrs.Me.Role.Logged == Rol_STD) if (Gbl.Usrs.Me.Role.Logged == Rol_STD)
Qst_UpdateQstScoreInDB (&Print->PrintedQuestions[QstInd]); TstPrn_UpdateQstScoreInDB (&Print->PrintedQuestions[QstInd]);
/***** Destroy test question *****/ /***** Destroy test question *****/
Qst_QstDestructor (&Question); Qst_QstDestructor (&Question);
@ -796,7 +798,7 @@ void TstPrn_ComputeScoresAndStoreQuestionsOfPrint (struct TstPrn_Print *Print,
/* Update the number of hits and the score of this question in tests database */ /* Update the number of hits and the score of this question in tests database */
if (UpdateQstScore) if (UpdateQstScore)
Qst_UpdateQstScoreInDB (&Print->PrintedQuestions[QstInd]); TstPrn_UpdateQstScoreInDB (&Print->PrintedQuestions[QstInd]);
} }
} }
@ -822,6 +824,32 @@ void TstPrn_ComputeAnswerScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
TstPrn_GetCorrectAndComputeAnsScore[Question->Answer.Type] (PrintedQuestion,Question); TstPrn_GetCorrectAndComputeAnsScore[Question->Answer.Type] (PrintedQuestion,Question);
} }
/*****************************************************************************/
/*********************** Update the score of a question **********************/
/*****************************************************************************/
static void TstPrn_UpdateQstScoreInDB (struct TstPrn_PrintedQuestion *PrintedQuestion)
{
/***** Update number of clicks and score of the question *****/
Str_SetDecimalPointToUS (); // To print the floating point as a dot
if (PrintedQuestion->StrAnswers[0]) // User's answer is not blank
DB_QueryUPDATE ("can not update the score of a question",
"UPDATE tst_questions"
" SET NumHits=NumHits+1,"
"NumHitsNotBlank=NumHitsNotBlank+1,"
"Score=Score+(%.15lg)"
" WHERE QstCod=%ld",
PrintedQuestion->Score,
PrintedQuestion->QstCod);
else // User's answer is blank
DB_QueryUPDATE ("can not update the score of a question",
"UPDATE tst_questions"
" SET NumHits=NumHits+1"
" WHERE QstCod=%ld",
PrintedQuestion->QstCod);
Str_SetDecimalPointToLocal (); // Return to local system
}
/*****************************************************************************/ /*****************************************************************************/
/******* Get correct answer and compute score for each type of answer ********/ /******* Get correct answer and compute score for each type of answer ********/
/*****************************************************************************/ /*****************************************************************************/

View File

@ -29,6 +29,7 @@
#include "swad_question.h" #include "swad_question.h"
#include "swad_question_type.h" #include "swad_question_type.h"
#include "swad_test.h"
#include "swad_test_config.h" #include "swad_test_config.h"
#include "swad_test_visibility.h" #include "swad_test_visibility.h"
#include "swad_user.h" #include "swad_user.h"