mirror of https://github.com/acanas/swad-core.git
Version 21.44: Oct 25, 2021 Functions moved to module swad_question.
This commit is contained in:
parent
b1854d0dea
commit
3bfa2807fe
12
swad_API.c
12
swad_API.c
|
@ -4240,7 +4240,7 @@ static int API_GetTstQuestions (struct soap *soap,
|
|||
long CrsCod,long BeginTime,
|
||||
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_ROW row;
|
||||
unsigned NumRow;
|
||||
|
@ -4305,7 +4305,7 @@ static int API_GetTstQuestions (struct soap *soap,
|
|||
getTestsOut->questionsArray.__ptr[NumRow].answerType =
|
||||
soap_malloc (soap,Qst_MAX_BYTES_ANSWER_TYPE + 1);
|
||||
Str_Copy (getTestsOut->questionsArray.__ptr[NumRow].answerType,
|
||||
Tst_StrAnswerTypesXML[AnswerType],
|
||||
Qst_StrAnswerTypesXML[AnswerType],
|
||||
Qst_MAX_BYTES_ANSWER_TYPE);
|
||||
|
||||
/* Get shuffle (row[2]) */
|
||||
|
@ -4340,7 +4340,7 @@ static int API_GetTstAnswers (struct soap *soap,
|
|||
long CrsCod,long BeginTime,
|
||||
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_ROW row;
|
||||
unsigned NumRow,NumRows;
|
||||
|
@ -4440,7 +4440,7 @@ static int API_GetTstQuestionTags (struct soap *soap,
|
|||
long CrsCod,long BeginTime,
|
||||
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_ROW row;
|
||||
unsigned NumRow,NumRows;
|
||||
|
@ -4527,7 +4527,7 @@ int swad__getTrivialQuestion (struct soap *soap,
|
|||
char *wsKey,char *degrees,float lowerScore,float upperScore, // input
|
||||
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;
|
||||
const char *Ptr;
|
||||
char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1];
|
||||
|
@ -4653,7 +4653,7 @@ int swad__getTrivialQuestion (struct soap *soap,
|
|||
getTrivialQuestionOut->question.answerType =
|
||||
soap_malloc (soap,Qst_MAX_BYTES_ANSWER_TYPE + 1);
|
||||
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]) */
|
||||
getTrivialQuestionOut->question.shuffle = (row[2][0] == 'Y') ? 1 :
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
#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 JS_FILE "swad20.69.1.js"
|
||||
/*
|
||||
TODO: Rename CENTRE to CENTER in help wiki.
|
||||
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.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)
|
||||
|
|
|
@ -861,7 +861,7 @@ void Exa_DB_RemoveAllSetsFromCrs (long CrsCod)
|
|||
|
||||
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] =
|
||||
{
|
||||
[Qst_INVALID_QUESTION] = 'Y',
|
||||
|
@ -878,7 +878,7 @@ long Exa_DB_AddQuestionToSet (long SetCod,const struct Qst_Question *Question,lo
|
|||
"'%s','%s',%ld)",
|
||||
SetCod,
|
||||
CharInvalid[Question->Validity],
|
||||
Tst_StrAnswerTypesDB[Question->Answer.Type],
|
||||
Qst_DB_StrAnswerTypes[Question->Answer.Type],
|
||||
Question->Answer.Shuffle ? 'Y' :
|
||||
'N',
|
||||
Question->Stem,
|
||||
|
|
311
swad_question.c
311
swad_question.c
|
@ -33,18 +33,18 @@
|
|||
// #include <stddef.h> // For NULL
|
||||
// #include <stdio.h> // For asprintf
|
||||
// #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/types.h> // For mkdir
|
||||
|
||||
// #include "swad_action.h"
|
||||
// #include "swad_box.h"
|
||||
// #include "swad_database.h"
|
||||
// #include "swad_error.h"
|
||||
#include "swad_database.h"
|
||||
#include "swad_error.h"
|
||||
// #include "swad_exam_set.h"
|
||||
// #include "swad_figure.h"
|
||||
// #include "swad_form.h"
|
||||
// #include "swad_global.h"
|
||||
#include "swad_global.h"
|
||||
// #include "swad_hierarchy_level.h"
|
||||
// #include "swad_HTML.h"
|
||||
// #include "swad_ID.h"
|
||||
|
@ -53,9 +53,9 @@
|
|||
// #include "swad_media.h"
|
||||
// #include "swad_parameter.h"
|
||||
#include "swad_question.h"
|
||||
// #include "swad_question_import.h"
|
||||
#include "swad_question_import.h"
|
||||
// #include "swad_tag_database.h"
|
||||
// #include "swad_test.h"
|
||||
#include "swad_test.h"
|
||||
// #include "swad_test_config.h"
|
||||
// #include "swad_test_print.h"
|
||||
// #include "swad_test_visibility.h"
|
||||
|
@ -67,6 +67,27 @@
|
|||
/***************************** 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 ******************************/
|
||||
/*****************************************************************************/
|
||||
|
@ -89,6 +110,250 @@ extern struct Globals Gbl;
|
|||
/***************************** 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 ******************/
|
||||
/*****************************************************************************/
|
||||
|
@ -123,3 +388,37 @@ void Qst_ChangeFormatAnswersFeedback (struct Qst_Question *Question)
|
|||
Question->Answer.Options[NumOpt].Feedback,
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -30,10 +30,13 @@
|
|||
#include <stdbool.h> // For boolean type
|
||||
#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_string.h"
|
||||
#include "swad_tag.h"
|
||||
// #include "swad_test.h"
|
||||
// #include "swad_test_config.h"
|
||||
// #include "swad_test_visibility.h"
|
||||
// #include "swad_user.h"
|
||||
|
@ -42,24 +45,30 @@
|
|||
/***************************** 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_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 ********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
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
|
||||
typedef enum
|
||||
{
|
||||
|
@ -67,19 +76,6 @@ typedef enum
|
|||
Qst_VALID_QUESTION,
|
||||
} 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
|
||||
{
|
||||
long QstCod;
|
||||
|
@ -110,11 +106,29 @@ struct Qst_Question
|
|||
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 *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
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_ChangeFormatAnswersFeedback (struct Qst_Question *Question);
|
||||
|
||||
Qst_AnswerType_t Qst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeDB);
|
||||
Qst_AnswerType_t Qst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -67,7 +67,7 @@ extern struct Globals Gbl;
|
|||
/***************************** Private prototypes ****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
static void QstImp_PutParamsExportQsts (void *Test);
|
||||
static void QstImp_PutParamsExportQsts (void *Questions);
|
||||
static void QstImp_PutCreateXMLParam (void);
|
||||
|
||||
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 *****************/
|
||||
/*****************************************************************************/
|
||||
|
||||
void QstImp_PutIconToExportQuestions (struct Tst_Test *Test)
|
||||
void QstImp_PutIconToExportQuestions (struct Qst_Questions *Questions)
|
||||
{
|
||||
extern const char *Txt_Export_questions;
|
||||
|
||||
/***** Put a link to create a file with questions *****/
|
||||
Lay_PutContextualLinkOnlyIcon (ActLstTstQst,NULL,
|
||||
QstImp_PutParamsExportQsts,Test,
|
||||
QstImp_PutParamsExportQsts,Questions,
|
||||
"file-import.svg",
|
||||
Txt_Export_questions);
|
||||
}
|
||||
|
@ -105,13 +105,13 @@ void QstImp_PutIconToExportQuestions (struct Tst_Test *Test)
|
|||
/****************** 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_PutHiddenParamUnsigned (NULL,"Order",(unsigned) (((struct Tst_Test *) Test)->SelectedOrder));
|
||||
Par_PutHiddenParamUnsigned (NULL,"Order",(unsigned) (((struct Qst_Questions *) Questions)->SelectedOrder));
|
||||
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)
|
||||
{
|
||||
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
||||
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
||||
extern const char *Txt_NEW_LINE;
|
||||
|
||||
if (Qst_GetQstDataFromDB (Question))
|
||||
{
|
||||
/***** Write the answer type *****/
|
||||
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 *****/
|
||||
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)
|
||||
{
|
||||
extern const char *Tst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
||||
extern const char *Qst_StrAnswerTypesXML[Qst_NUM_ANS_TYPES];
|
||||
Qst_AnswerType_t AnsType;
|
||||
|
||||
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++)
|
||||
// comparison must be case insensitive, because users can edit XML
|
||||
if (!strcasecmp (StrAnsTypeXML,Tst_StrAnswerTypesXML[AnsType]))
|
||||
if (!strcasecmp (StrAnsTypeXML,Qst_StrAnswerTypesXML[AnsType]))
|
||||
return AnsType;
|
||||
|
||||
Err_WrongAnswerExit ();
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
/********************************* Headers ***********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "swad_test.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/***************************** Public constants ******************************/
|
||||
/*****************************************************************************/
|
||||
|
@ -39,7 +41,7 @@
|
|||
/***************************** Public prototypes *****************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
void QstImp_PutIconToExportQuestions (struct Tst_Test *Test);
|
||||
void QstImp_PutIconToExportQuestions (struct Qst_Questions *Questions);
|
||||
bool QstImp_GetCreateXMLParamFromForm (void);
|
||||
void QstImp_PutIconToImportQuestions (void);
|
||||
void QstImp_CreateXML (unsigned long NumRows,MYSQL_RES *mysql_res);
|
||||
|
|
|
@ -31,12 +31,33 @@
|
|||
#include "swad_tag.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/***************************** Public constants ******************************/
|
||||
/************************* Public constants and types ************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/******************************* Public types ********************************/
|
||||
/*****************************************************************************/
|
||||
#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;
|
||||
|
||||
|
||||
#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 *****************************/
|
||||
|
|
796
swad_test.c
796
swad_test.c
File diff suppressed because it is too large
Load Diff
53
swad_test.h
53
swad_test.h
|
@ -45,32 +45,6 @@
|
|||
/******************************* 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
|
||||
{
|
||||
Tst_SHOW_TEST_TO_ANSWER, // Showing a test to a student
|
||||
|
@ -98,6 +72,10 @@ struct Tst_Stats
|
|||
/*****************************************************************************/
|
||||
|
||||
void Tst_RequestTest (void);
|
||||
|
||||
void Qst_Constructor (struct Qst_Questions *Questions);
|
||||
void Qst_Destructor (struct Qst_Questions *Questions);
|
||||
|
||||
void Tst_ShowNewTest (void);
|
||||
void Tst_ReceiveTestDraft (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_RequestEditQsts (void);
|
||||
void Qst_ShowFormRequestEditQsts (struct Qst_Questions *Questions);
|
||||
void Qst_RequestSelectQstsForExamSet (struct Exa_Exams *Exams);
|
||||
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_ListQuestionsToSelectForExamSet (struct Exa_Exams *Exams);
|
||||
void Qst_ListQuestionsToSelectForGame (struct Gam_Games *Games);
|
||||
void Qst_ListOneOrMoreQstsForEdition (struct Qst_Questions *Questions,
|
||||
MYSQL_RES *mysql_res);
|
||||
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);
|
||||
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);
|
||||
|
||||
bool Tst_GetParamsTst (struct Qst_Questions *Questions,
|
||||
Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions);
|
||||
void Tst_ShowFormConfig (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);
|
||||
bool Qst_GetQstDataFromDB (struct Qst_Question *Question);
|
||||
Qst_AnswerType_t Qst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeDB);
|
||||
void Qst_ReceiveQst (void);
|
||||
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_UpdateQstScoreInDB (struct TstPrn_PrintedQuestion *PrintedQuestion);
|
||||
|
||||
void Tst_RemoveCrsTests (long CrsCod);
|
||||
void Qst_RemoveCrsQsts (long CrsCod);
|
||||
|
||||
|
|
|
@ -115,6 +115,8 @@ static void TstPrn_WriteQstAndAnsExam (struct UsrData *UsrDat,
|
|||
bool QuestionExists,
|
||||
unsigned Visibility);
|
||||
|
||||
static void TstPrn_UpdateQstScoreInDB (struct TstPrn_PrintedQuestion *PrintedQuestion);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
static void TstPrn_GetCorrectAndComputeIntAnsScore (struct TstPrn_PrintedQuestion *PrintedQuestion,
|
||||
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 *****/
|
||||
if (Gbl.Usrs.Me.Role.Logged == Rol_STD)
|
||||
Qst_UpdateQstScoreInDB (&Print->PrintedQuestions[QstInd]);
|
||||
TstPrn_UpdateQstScoreInDB (&Print->PrintedQuestions[QstInd]);
|
||||
|
||||
/***** Destroy test 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 */
|
||||
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);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/*********************** 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 ********/
|
||||
/*****************************************************************************/
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
#include "swad_question.h"
|
||||
#include "swad_question_type.h"
|
||||
#include "swad_test.h"
|
||||
#include "swad_test_config.h"
|
||||
#include "swad_test_visibility.h"
|
||||
#include "swad_user.h"
|
||||
|
|
Loading…
Reference in New Issue