Version19.217

This commit is contained in:
acanas 2020-05-07 18:33:26 +02:00
parent a04402a458
commit dc919206d6
22 changed files with 924 additions and 733 deletions

View File

@ -58,8 +58,8 @@ OBJS = swad_account.o swad_action.o swad_agenda.o swad_alert.o \
swad_scope.o swad_search.o swad_session.o swad_setting.o \ swad_scope.o swad_search.o swad_session.o swad_setting.o \
swad_statistic.o swad_string.o swad_survey.o swad_syllabus.o \ swad_statistic.o swad_string.o swad_survey.o swad_syllabus.o \
swad_system_config.o \ swad_system_config.o \
swad_tab.o swad_test.o swad_test_config.o swad_test_exam.o \ swad_tab.o swad_test.o swad_test_config.o swad_test_import.o \
swad_test_import.o swad_test_visibility.o swad_theme.o swad_timeline.o \ swad_test_print.o swad_test_visibility.o swad_theme.o swad_timeline.o \
swad_timetable.o \ swad_timetable.o \
swad_user.o \ swad_user.o \
swad_xml.o \ swad_xml.o \

View File

@ -2654,9 +2654,9 @@ table.CELLS_PAD_10 > tbody > tr > td {padding:10px;}
text-align:center; text-align:center;
vertical-align:middle; vertical-align:middle;
} }
.TEST_EXA {color:#202020; font-size:12pt;} .TEST_EXA {color:#202020; font-size:12pt;}
.TEST_EXA_LIGHT {color:#a0a0a0; font-size:12pt;} .TEST_EXA_LIGHT {color:#a0a0a0; font-size:12pt;}
.TEST_EDI {color:#202020; font-size:12pt;} .TEST_EDI {color:#202020; font-size:12pt;}
.TEST_EDI_LIGHT {color:#a0a0a0; font-size:12pt;} .TEST_EDI_LIGHT {color:#a0a0a0; font-size:12pt;}
.TEST_TAG_LIST .TEST_TAG_LIST
@ -2744,6 +2744,21 @@ table.CELLS_PAD_10 > tbody > tr > td {padding:10px;}
} }
/*********************************** Exams ***********************************/ /*********************************** Exams ***********************************/
.EXA_SET_TITLE
{
text-align:left;
vertical-align:top;
color:black;
font-size:16pt;
}
.EXA_SET_NUM_QSTS
{
text-align:right;
vertical-align:top;
color:#404040;
font-size:12pt;
}
.EXA_BG .EXA_BG
{ {
background-image:url("/swad/icon/bg.jpg"); background-image:url("/swad/icon/bg.jpg");

View File

@ -3955,7 +3955,7 @@ int swad__sendNotice (struct soap *soap,
/****************** Return test configuration in a course ********************/ /****************** Return test configuration in a course ********************/
/*****************************************************************************/ /*****************************************************************************/
#define TstRes_MAX_BYTES_FEEDBACK_TYPE 32 #define TstPrn_MAX_BYTES_FEEDBACK_TYPE 32
int swad__getTestConfig (struct soap *soap, int swad__getTestConfig (struct soap *soap,
char *wsKey,int courseCode, // input char *wsKey,int courseCode, // input
@ -4010,7 +4010,7 @@ int swad__getTestConfig (struct soap *soap,
getTestConfigOut->visibility = TstVis_MIN_VISIBILITY; getTestConfigOut->visibility = TstVis_MIN_VISIBILITY;
/* TODO: Remove these lines in 2021 */ /* TODO: Remove these lines in 2021 */
getTestConfigOut->feedback = (char *) soap_malloc (soap,TstRes_MAX_BYTES_FEEDBACK_TYPE + 1); getTestConfigOut->feedback = (char *) soap_malloc (soap,TstPrn_MAX_BYTES_FEEDBACK_TYPE + 1);
getTestConfigOut->feedback[0] = '\0'; getTestConfigOut->feedback[0] = '\0';
/***** Get test configuration *****/ /***** Get test configuration *****/
@ -4028,23 +4028,23 @@ int swad__getTestConfig (struct soap *soap,
if (!TstVis_IsVisibleTotalScore (TstCfg_GetConfigVisibility ())) if (!TstVis_IsVisibleTotalScore (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback, Str_Copy (getTestConfigOut->feedback,
"nothing", "nothing",
TstRes_MAX_BYTES_FEEDBACK_TYPE); TstPrn_MAX_BYTES_FEEDBACK_TYPE);
else if (!TstVis_IsVisibleEachQstScore (TstCfg_GetConfigVisibility ())) else if (!TstVis_IsVisibleEachQstScore (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback, Str_Copy (getTestConfigOut->feedback,
"totalResult", "totalResult",
TstRes_MAX_BYTES_FEEDBACK_TYPE); TstPrn_MAX_BYTES_FEEDBACK_TYPE);
else if (!TstVis_IsVisibleCorrectAns (TstCfg_GetConfigVisibility ())) else if (!TstVis_IsVisibleCorrectAns (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback, Str_Copy (getTestConfigOut->feedback,
"eachResult", "eachResult",
TstRes_MAX_BYTES_FEEDBACK_TYPE); TstPrn_MAX_BYTES_FEEDBACK_TYPE);
else if (!TstVis_IsVisibleFeedbackTxt (TstCfg_GetConfigVisibility ())) else if (!TstVis_IsVisibleFeedbackTxt (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback, Str_Copy (getTestConfigOut->feedback,
"eachGoodBad", "eachGoodBad",
TstRes_MAX_BYTES_FEEDBACK_TYPE); TstPrn_MAX_BYTES_FEEDBACK_TYPE);
else else
Str_Copy (getTestConfigOut->feedback, Str_Copy (getTestConfigOut->feedback,
"fullFeedback", "fullFeedback",
TstRes_MAX_BYTES_FEEDBACK_TYPE); TstPrn_MAX_BYTES_FEEDBACK_TYPE);
/***** Get number of tests *****/ /***** Get number of tests *****/
if (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES && if (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES &&

View File

@ -50,7 +50,7 @@
#include "swad_profile.h" #include "swad_profile.h"
#include "swad_project.h" #include "swad_project.h"
#include "swad_report.h" #include "swad_report.h"
#include "swad_test_exam.h" #include "swad_test_print.h"
#include "swad_timeline.h" #include "swad_timeline.h"
/*****************************************************************************/ /*****************************************************************************/
@ -1082,7 +1082,7 @@ void Acc_CompletelyEliminateAccount (struct UsrData *UsrDat,
UsrDat->FullName); UsrDat->FullName);
/***** Remove test results made by user in all courses *****/ /***** Remove test results made by user in all courses *****/
TstRes_RemoveExamsMadeByUsrInAllCrss (UsrDat->UsrCod); TstPrn_RemoveExamsMadeByUsrInAllCrss (UsrDat->UsrCod);
/***** Remove user's notifications *****/ /***** Remove user's notifications *****/
Ntf_RemoveUsrNtfs (UsrDat->UsrCod); Ntf_RemoveUsrNtfs (UsrDat->UsrCod);

View File

@ -670,12 +670,12 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] =
[ActRenTag ] = { 143,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_RenameTag ,NULL}, [ActRenTag ] = { 143,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_RenameTag ,NULL},
[ActRcvCfgTst ] = { 454,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstCfg_ReceiveConfigTst ,NULL}, [ActRcvCfgTst ] = { 454,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstCfg_ReceiveConfigTst ,NULL},
[ActReqSeeMyTstRes ] = {1083,-1,TabUnk,ActReqTst ,0x208,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,Dat_SetIniEndDates ,TstRes_SelDatesToSeeMyExams ,NULL}, [ActReqSeeMyTstRes ] = {1083,-1,TabUnk,ActReqTst ,0x208,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,Dat_SetIniEndDates ,TstPrn_SelDatesToSeeMyExams ,NULL},
[ActSeeMyTstRes ] = {1084,-1,TabUnk,ActReqTst ,0x208,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstRes_ShowMyExams ,NULL}, [ActSeeMyTstRes ] = {1084,-1,TabUnk,ActReqTst ,0x208,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstPrn_ShowMyExams ,NULL},
[ActSeeOneTstResMe ] = {1085,-1,TabUnk,ActReqTst ,0x208,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstRes_ShowOneExam ,NULL}, [ActSeeOneTstResMe ] = {1085,-1,TabUnk,ActReqTst ,0x208,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstPrn_ShowOneExam ,NULL},
[ActReqSeeUsrTstRes ] = {1080,-1,TabUnk,ActReqTst ,0x230,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,Dat_SetIniEndDates ,TstRes_SelUsrsToViewUsrsExams ,NULL}, [ActReqSeeUsrTstRes ] = {1080,-1,TabUnk,ActReqTst ,0x230,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,Dat_SetIniEndDates ,TstPrn_SelUsrsToViewUsrsExams ,NULL},
[ActSeeUsrTstRes ] = {1081,-1,TabUnk,ActReqTst ,0x230,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstRes_GetUsrsAndShowExams ,NULL}, [ActSeeUsrTstRes ] = {1081,-1,TabUnk,ActReqTst ,0x230,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstPrn_GetUsrsAndShowExams ,NULL},
[ActSeeOneTstResOth ] = {1082,-1,TabUnk,ActReqTst ,0x230,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstRes_ShowOneExam ,NULL}, [ActSeeOneTstResOth ] = {1082,-1,TabUnk,ActReqTst ,0x230,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstPrn_ShowOneExam ,NULL},
[ActSeeExa ] = {1849,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_SeeOneExam ,NULL}, [ActSeeExa ] = {1849,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_SeeOneExam ,NULL},

View File

@ -548,11 +548,11 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD: En OpenSWAD:
ps2pdf source.ps destination.pdf ps2pdf source.ps destination.pdf
*/ */
#define Log_PLATFORM_VERSION "SWAD 19.216.1 (2020-05-07)" #define Log_PLATFORM_VERSION "SWAD 19.217 (2020-05-07)"
#define CSS_FILE "swad19.193.1.css" #define CSS_FILE "swad19.217.css"
#define JS_FILE "swad19.193.1.js" #define JS_FILE "swad19.193.1.js"
/* /*
Version 19.217: May 07, 2020 Generate and show questions of each set in an exam print. (? lines) Version 19.217: May 07, 2020 Generate and show questions of each set in an exam print. Not finished. (302124 lines)
Version 19.216.1: May 07, 2020 Fixed bug in edition of exam questions, reported by Antonio Cañas Martínez. Version 19.216.1: May 07, 2020 Fixed bug in edition of exam questions, reported by Antonio Cañas Martínez.
Changes in some texts. (301957 lines) Changes in some texts. (301957 lines)
Version 19.216: May 07, 2020 New module exam_print to generate new exam prints. (301949 lines) Version 19.216: May 07, 2020 New module exam_print to generate new exam prints. (301949 lines)

View File

@ -40,6 +40,7 @@
#include "swad_figure_cache.h" #include "swad_figure_cache.h"
#include "swad_form.h" #include "swad_form.h"
#include "swad_forum.h" #include "swad_forum.h"
#include "swad_game.h"
#include "swad_global.h" #include "swad_global.h"
#include "swad_help.h" #include "swad_help.h"
#include "swad_HTML.h" #include "swad_HTML.h"
@ -49,7 +50,7 @@
#include "swad_project.h" #include "swad_project.h"
#include "swad_search.h" #include "swad_search.h"
#include "swad_survey.h" #include "swad_survey.h"
#include "swad_test_exam.h" #include "swad_test.h"
/*****************************************************************************/ /*****************************************************************************/
/************** External global variables from others modules ****************/ /************** External global variables from others modules ****************/
@ -1988,7 +1989,7 @@ static void Crs_EmptyCourseCompletely (long CrsCod)
Svy_RemoveSurveys (Hie_CRS,CrsCod); Svy_RemoveSurveys (Hie_CRS,CrsCod);
/***** Remove all test exams made in the course *****/ /***** Remove all test exams made in the course *****/
TstRes_RemoveCrsExams (CrsCod); TstPrn_RemoveCrsExams (CrsCod);
/***** Remove all tests questions in the course *****/ /***** Remove all tests questions in the course *****/
Tst_RemoveCrsTests (CrsCod); Tst_RemoveCrsTests (CrsCod);

View File

@ -1768,7 +1768,7 @@ mysql> DESCRIBE mch_indexes;
DB_CreateTable ("CREATE TABLE IF NOT EXISTS mch_indexes (" DB_CreateTable ("CREATE TABLE IF NOT EXISTS mch_indexes ("
"MchCod INT NOT NULL," "MchCod INT NOT NULL,"
"QstInd INT NOT NULL," "QstInd INT NOT NULL,"
"Indexes TEXT NOT NULL," // TstRes_MAX_BYTES_INDEXES_ONE_QST "Indexes TEXT NOT NULL," // TstPrn_MAX_BYTES_INDEXES_ONE_QST
"UNIQUE INDEX(MchCod,QstInd))"); "UNIQUE INDEX(MchCod,QstInd))");
/***** Table mch_results *****/ /***** Table mch_results *****/
@ -3189,8 +3189,8 @@ mysql> DESCRIBE tst_exam_questions;
"QstCod INT NOT NULL," "QstCod INT NOT NULL,"
"QstInd INT NOT NULL," "QstInd INT NOT NULL,"
"Score DOUBLE PRECISION NOT NULL DEFAULT 0," "Score DOUBLE PRECISION NOT NULL DEFAULT 0,"
"Indexes TEXT NOT NULL," // TstRes_MAX_BYTES_INDEXES_ONE_QST "Indexes TEXT NOT NULL," // TstPrn_MAX_BYTES_INDEXES_ONE_QST
"Answers TEXT NOT NULL," // TstRes_MAX_BYTES_ANSWERS_ONE_QST "Answers TEXT NOT NULL," // TstPrn_MAX_BYTES_ANSWERS_ONE_QST
"UNIQUE INDEX(ExaCod,QstCod))"); "UNIQUE INDEX(ExaCod,QstCod))");
/***** Table tst_exams *****/ /***** Table tst_exams *****/

View File

@ -47,7 +47,7 @@
#include "swad_parameter.h" #include "swad_parameter.h"
#include "swad_photo.h" #include "swad_photo.h"
#include "swad_role.h" #include "swad_role.h"
#include "swad_test_exam.h" #include "swad_test_print.h"
#include "swad_user.h" #include "swad_user.h"
/*****************************************************************************/ /*****************************************************************************/
@ -4128,7 +4128,7 @@ static void Enr_EffectivelyRemUsrFromCrs (struct UsrData *UsrDat,
Brw_RemoveSomeInfoAboutCrsUsrFilesFromDB (UsrDat->UsrCod,Crs->CrsCod); Brw_RemoveSomeInfoAboutCrsUsrFilesFromDB (UsrDat->UsrCod,Crs->CrsCod);
/***** Remove test results made by user in course *****/ /***** Remove test results made by user in course *****/
TstRes_RemoveExamsMadeByUsrInCrs (UsrDat->UsrCod,Crs->CrsCod); TstPrn_RemoveExamsMadeByUsrInCrs (UsrDat->UsrCod,Crs->CrsCod);
/***** Set all the notifications for this user in this course as removed, /***** Set all the notifications for this user in this course as removed,
except notifications about new messages *****/ except notifications about new messages *****/

View File

@ -239,7 +239,7 @@ static void ExaEvt_GetNumParticipants (struct ExaEvt_Event *Event);
static void ExaEvt_RemoveMyAnswerToEventQuestion (const struct ExaEvt_Event *Event); static void ExaEvt_RemoveMyAnswerToEventQuestion (const struct ExaEvt_Event *Event);
static void ExaEvt_ComputeScore (struct TstRes_Result *Result); static void ExaEvt_ComputeScore (struct TstPrn_Print *Print);
static unsigned ExaEvt_GetNumUsrsWhoHaveAnswerEvt (long EvtCod); static unsigned ExaEvt_GetNumUsrsWhoHaveAnswerEvt (long EvtCod);
@ -1934,7 +1934,7 @@ static void ExaEvt_ReorderAnswer (long EvtCod,unsigned QstInd,
long LongNum; long LongNum;
unsigned AnsInd; unsigned AnsInd;
char StrOneAnswer[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; char StrOneAnswer[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
char StrAnswersOneQst[TstRes_MAX_BYTES_ANSWERS_ONE_QST + 1]; char StrAnswersOneQst[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1];
***** Initialize list of answers to empty string ***** ***** Initialize list of answers to empty string *****
StrAnswersOneQst[0] = '\0'; StrAnswersOneQst[0] = '\0';
@ -1967,9 +1967,9 @@ static void ExaEvt_ReorderAnswer (long EvtCod,unsigned QstInd,
* Concatenate answer index to list of answers * * Concatenate answer index to list of answers *
if (NumAns) if (NumAns)
Str_Concat (StrAnswersOneQst,",", Str_Concat (StrAnswersOneQst,",",
TstRes_MAX_BYTES_ANSWERS_ONE_QST); TstPrn_MAX_BYTES_ANSWERS_ONE_QST);
Str_Concat (StrAnswersOneQst,StrOneAnswer, Str_Concat (StrAnswersOneQst,StrOneAnswer,
TstRes_MAX_BYTES_ANSWERS_ONE_QST); TstPrn_MAX_BYTES_ANSWERS_ONE_QST);
} }
***** Free structure that stores the query result ***** ***** Free structure that stores the query result *****
@ -1993,7 +1993,7 @@ void ExaEvt_GetIndexes (long EvtCod,unsigned QstInd,
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
char StrIndexesOneQst[TstRes_MAX_BYTES_INDEXES_ONE_QST + 1]; char StrIndexesOneQst[TstPrn_MAX_BYTES_INDEXES_ONE_QST + 1];
/***** Get indexes for a question from database *****/ /***** Get indexes for a question from database *****/
if (!DB_QuerySELECT (&mysql_res,"can not get data of a question", if (!DB_QuerySELECT (&mysql_res,"can not get data of a question",
@ -2006,14 +2006,14 @@ void ExaEvt_GetIndexes (long EvtCod,unsigned QstInd,
/* Get indexes (row[0]) */ /* Get indexes (row[0]) */
Str_Copy (StrIndexesOneQst,row[0], Str_Copy (StrIndexesOneQst,row[0],
TstRes_MAX_BYTES_INDEXES_ONE_QST); TstPrn_MAX_BYTES_INDEXES_ONE_QST);
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
/***** Get indexes from string *****/ /***** Get indexes from string *****/
Par_ReplaceCommaBySeparatorMultiple (StrIndexesOneQst); Par_ReplaceCommaBySeparatorMultiple (StrIndexesOneQst);
TstRes_GetIndexesFromStr (StrIndexesOneQst,Indexes); TstPrn_GetIndexesFromStr (StrIndexesOneQst,Indexes);
} }
/*****************************************************************************/ /*****************************************************************************/
@ -4212,7 +4212,7 @@ void ExaEvt_ReceiveQuestionAnswer (void)
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION];
struct ExaEvt_UsrAnswer PreviousUsrAnswer; struct ExaEvt_UsrAnswer PreviousUsrAnswer;
struct ExaEvt_UsrAnswer UsrAnswer; struct ExaEvt_UsrAnswer UsrAnswer;
struct TstRes_Result Result; struct TstPrn_Print Print;
/***** Reset event *****/ /***** Reset event *****/
ExaEvt_ResetEvent (&Event); ExaEvt_ResetEvent (&Event);
@ -4271,8 +4271,8 @@ void ExaEvt_ReceiveQuestionAnswer (void)
/***** Update student's exam event result *****/ /***** Update student's exam event result *****/
ExaRes_GetExamResultQuestionsFromDB (Event.EvtCod,Gbl.Usrs.Me.UsrDat.UsrCod, ExaRes_GetExamResultQuestionsFromDB (Event.EvtCod,Gbl.Usrs.Me.UsrDat.UsrCod,
&Result); &Print);
ExaEvt_ComputeScore (&Result); ExaEvt_ComputeScore (&Print);
Str_SetDecimalPointToUS (); // To print the floating point as a dot Str_SetDecimalPointToUS (); // To print the floating point as a dot
if (DB_QueryCOUNT ("can not get if exam event result exists", if (DB_QueryCOUNT ("can not get if exam event result exists",
@ -4287,9 +4287,9 @@ void ExaEvt_ReceiveQuestionAnswer (void)
"NumQstsNotBlank=%u," "NumQstsNotBlank=%u,"
"Score='%.15lg'" "Score='%.15lg'"
" WHERE EvtCod=%ld AND UsrCod=%ld", " WHERE EvtCod=%ld AND UsrCod=%ld",
Result.NumQsts, Print.NumQsts,
Result.NumQstsNotBlank, Print.NumQstsNotBlank,
Result.Score, Print.Score,
Event.EvtCod,Gbl.Usrs.Me.UsrDat.UsrCod); Event.EvtCod,Gbl.Usrs.Me.UsrDat.UsrCod);
else // Result doesn't exist else // Result doesn't exist
/* Create result */ /* Create result */
@ -4305,9 +4305,9 @@ void ExaEvt_ReceiveQuestionAnswer (void)
"%u," // NumQstsNotBlank "%u," // NumQstsNotBlank
"'%.15lg')", // Score "'%.15lg')", // Score
Event.EvtCod,Gbl.Usrs.Me.UsrDat.UsrCod, Event.EvtCod,Gbl.Usrs.Me.UsrDat.UsrCod,
Result.NumQsts, Print.NumQsts,
Result.NumQstsNotBlank, Print.NumQstsNotBlank,
Result.Score); Print.Score);
Str_SetDecimalPointToLocal (); // Return to local system Str_SetDecimalPointToLocal (); // Return to local system
} }
@ -4333,25 +4333,25 @@ static void ExaEvt_RemoveMyAnswerToEventQuestion (const struct ExaEvt_Event *Eve
/******************** Compute exam event score for a student **********************/ /******************** Compute exam event score for a student **********************/
/*****************************************************************************/ /*****************************************************************************/
static void ExaEvt_ComputeScore (struct TstRes_Result *Result) static void ExaEvt_ComputeScore (struct TstPrn_Print *Print)
{ {
unsigned NumQst; unsigned NumQst;
struct Tst_Question Question; struct Tst_Question Question;
for (NumQst = 0, Result->Score = 0.0; for (NumQst = 0, Print->Score = 0.0;
NumQst < Result->NumQsts; NumQst < Print->NumQsts;
NumQst++) NumQst++)
{ {
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question); Tst_QstConstructor (&Question);
Question.QstCod = Result->Questions[NumQst].QstCod; Question.QstCod = Print->PrintedQuestions[NumQst].QstCod;
Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE; Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE;
/***** Compute score for this answer ******/ /***** Compute score for this answer ******/
TstRes_ComputeChoiceAnsScore (Result,NumQst,&Question); TstPrn_ComputeChoiceAnsScore (Print,NumQst,&Question);
/***** Update total score *****/ /***** Update total score *****/
Result->Score += Result->Questions[NumQst].Score; Print->Score += Print->PrintedQuestions[NumQst].Score;
/***** Destroy test question *****/ /***** Destroy test question *****/
Tst_QstDestructor (&Question); Tst_QstDestructor (&Question);

View File

@ -51,13 +51,22 @@ extern struct Globals Gbl;
/***************************** Private constants *****************************/ /***************************** Private constants *****************************/
/*****************************************************************************/ /*****************************************************************************/
#define ExaPrn_MAX_QUESTIONS_PER_EXAM_PRINT 100 // Absolute maximum number of questions in an exam print
/*****************************************************************************/ /*****************************************************************************/
/******************************* Private types *******************************/ /******************************* Private types *******************************/
/*****************************************************************************/ /*****************************************************************************/
struct ExaPrn_Print struct ExaPrn_Print
{ {
unsigned foo; long PrnCod; // Exam print code
time_t TimeUTC[Dat_NUM_START_END_TIME];
unsigned NumQsts; // Number of questions
unsigned NumQstsNotBlank; // Number of questions not blank
bool Sent; // This exam print has been sent or not?
// "Sent" means that user has clicked "Send" button after finishing
double Score; // Total score of the exam print
struct TstPrn_PrintedQuestion PrintedQuestions[ExaPrn_MAX_QUESTIONS_PER_EXAM_PRINT];
}; };
/*****************************************************************************/ /*****************************************************************************/
@ -72,11 +81,33 @@ struct ExaPrn_Print
/***************************** Private prototypes ****************************/ /***************************** Private prototypes ****************************/
/*****************************************************************************/ /*****************************************************************************/
static void ExaPrn_PrintConstructor (struct ExaPrn_Print *Print); static void ExaPrn_ResetPrint (struct ExaPrn_Print *Print);
static void ExaPrn_PrintDestructor (struct ExaPrn_Print *Print); static void ExaPrn_ResetPrintExceptPrnCod (struct ExaPrn_Print *Print);
static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam, static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam,
struct ExaPrn_Print *Print); struct ExaPrn_Print *Print);
static void ExaPrn_ShowQuestionsFromSet (struct ExaPrn_Print *Print,
struct ExaSet_Set *Set);
/*****************************************************************************/
/**************************** Reset exam print *******************************/
/*****************************************************************************/
static void ExaPrn_ResetPrint (struct ExaPrn_Print *Print)
{
Print->PrnCod = -1L;
ExaPrn_ResetPrintExceptPrnCod (Print);
}
static void ExaPrn_ResetPrintExceptPrnCod (struct ExaPrn_Print *Print)
{
Print->TimeUTC[Dat_START_TIME] =
Print->TimeUTC[Dat_END_TIME ] = (time_t) 0;
Print->NumQsts =
Print->NumQstsNotBlank = 0;
Print->Sent = false; // After creating an exam print, it's not sent
Print->Score = 0.0;
}
/*****************************************************************************/ /*****************************************************************************/
/******************* Generate print of an exam in an event *******************/ /******************* Generate print of an exam in an event *******************/
@ -94,13 +125,11 @@ void ExaPrn_ShowNewExamPrint (void)
Exa_ResetExams (&Exams); Exa_ResetExams (&Exams);
Exa_ResetExam (&Exam); Exa_ResetExam (&Exam);
ExaEvt_ResetEvent (&Event); ExaEvt_ResetEvent (&Event);
ExaPrn_ResetPrint (&Print);
/***** Get and check parameters *****/ /***** Get and check parameters *****/
ExaEvt_GetAndCheckParameters (&Exams,&Exam,&Event); ExaEvt_GetAndCheckParameters (&Exams,&Exam,&Event);
/***** Create print *****/
ExaPrn_PrintConstructor (&Print);
/***** Begin box *****/ /***** Begin box *****/
Box_BoxBegin (NULL,Exam.Title, Box_BoxBegin (NULL,Exam.Title,
NULL,NULL, NULL,NULL,
@ -118,35 +147,12 @@ void ExaPrn_ShowNewExamPrint (void)
/***** End table *****/ /***** End table *****/
HTM_TABLE_End (); HTM_TABLE_End ();
/***** Destroy print *****/
ExaPrn_PrintDestructor (&Print);
}
/*****************************************************************************/
/***************************** Print constructor *****************************/
/*****************************************************************************/
static void ExaPrn_PrintConstructor (struct ExaPrn_Print *Print)
{
Print->foo = 1;
}
/*****************************************************************************/
/****************************** Print destructor *****************************/
/*****************************************************************************/
static void ExaPrn_PrintDestructor (struct ExaPrn_Print *Print)
{
Print->foo = 1;
} }
/*****************************************************************************/ /*****************************************************************************/
/*********** Get questions for a new exam print from the database ************/ /*********** Get questions for a new exam print from the database ************/
/*****************************************************************************/ /*****************************************************************************/
#define ExaPrn_MAX_BYTES_QUERY_PRINT (16 * 1024 - 1)
static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam, static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam,
struct ExaPrn_Print *Print) struct ExaPrn_Print *Print)
{ {
@ -158,8 +164,6 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam,
unsigned NumSet; unsigned NumSet;
struct ExaSet_Set Set; struct ExaSet_Set Set;
Print->foo = 1;
/***** Get data of set of questions from database *****/ /***** Get data of set of questions from database *****/
NumSets = (unsigned) NumSets = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get sets of questions", DB_QuerySELECT (&mysql_res,"can not get sets of questions",
@ -178,8 +182,6 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam,
NumSet < NumSets; NumSet < NumSets;
NumSet++) NumSet++)
{ {
Gbl.RowEvenOdd = NumSet % 2;
/***** Create set of questions *****/ /***** Create set of questions *****/
ExaSet_ResetSet (&Set); ExaSet_ResetSet (&Set);
@ -200,26 +202,130 @@ static void ExaPrn_GetQuestionsForNewPrintFromDB (struct Exa_Exam *Exam,
Str_Copy (Set.Title,row[2], Str_Copy (Set.Title,row[2],
ExaSet_MAX_BYTES_TITLE); ExaSet_MAX_BYTES_TITLE);
/***** Begin row for this set *****/ /***** Title for this set *****/
/* Begin title for this set */
HTM_TR_Begin (NULL); HTM_TR_Begin (NULL);
HTM_TD_Begin ("colspan=\"2\"");
HTM_TABLE_BeginWide ();
/***** Title *****/ /* Title */
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"EXA_SET_TITLE\"");
HTM_Txt (Set.Title); HTM_Txt (Set.Title);
HTM_TD_End (); HTM_TD_End ();
/***** Number of questions to appear in exam print *****/ /* Number of questions to appear in exam print */
HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"EXA_SET_NUM_QSTS\"");
HTM_Unsigned (Set.NumQstsToPrint); HTM_Unsigned (Set.NumQstsToPrint);
HTM_NBSP (); HTM_NBSP ();
HTM_Txt (Set.NumQstsToPrint == 1 ? Txt_question : HTM_Txt (Set.NumQstsToPrint == 1 ? Txt_question :
Txt_questions); Txt_questions);
HTM_TD_End (); HTM_TD_End ();
/***** End first row *****/ /* End title for this set */
HTM_TABLE_End ();
HTM_TD_End ();
HTM_TR_End (); HTM_TR_End ();
/***** Questions in this set *****/
ExaPrn_ShowQuestionsFromSet (Print,&Set);
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
} }
/*****************************************************************************/
/************************ Show questions from a set **************************/
/*****************************************************************************/
static void ExaPrn_ShowQuestionsFromSet (struct ExaPrn_Print *Print,
struct ExaSet_Set *Set)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumQsts;
unsigned NumQst;
long QstCod;
Tst_AnswerType_t AnswerType;
bool Shuffle;
/***** Get questions from database *****/
NumQsts = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get questions from set",
"SELECT tst_questions.QstCod," // row[0]
"tst_questions.AnsType," // row[1]
"tst_questions.Shuffle" // row[2]
" FROM exa_questions,tst_questions"
" WHERE exa_questions.setCod=%ld"
" AND exa_questions.QstCod=tst_questions.QstCod"
" ORDER BY RAND(NOW())"
" LIMIT %u",
Set->SetCod,
Set->NumQstsToPrint);
/***** Questions in this set *****/
for (NumQst = 0;
NumQst < NumQsts;
NumQst++)
{
Gbl.RowEvenOdd = 1 - Gbl.RowEvenOdd;
/***** Get question data *****/
row = mysql_fetch_row (mysql_res);
/*
row[0] QstCod
row[1] AnsType
row[2] Shuffle
*/
/* Get question code (row[0]) */
QstCod = Str_ConvertStrCodToLongCod (row[0]);
/* Get answer type (row[1]) */
AnswerType = Tst_ConvertFromStrAnsTypDBToAnsTyp (row[1]);
/* Get shuffle (row[2]) */
Shuffle = (row[2][0] == 'Y');
/* Set indexes of answers */
switch (AnswerType)
{
case Tst_ANS_INT:
case Tst_ANS_FLOAT:
case Tst_ANS_TRUE_FALSE:
case Tst_ANS_TEXT:
Print->PrintedQuestions[NumQst].StrIndexes[0] = '\0';
break;
case Tst_ANS_UNIQUE_CHOICE:
case Tst_ANS_MULTIPLE_CHOICE:
/* If answer type is unique or multiple option,
generate indexes of answers depending on shuffle */
Tst_GenerateChoiceIndexesDependingOnShuffle (&Print->PrintedQuestions[NumQst],Shuffle);
break;
default:
break;
}
/* Reset user's answers.
Initially user has not answered the question ==> initially all the answers will be blank.
If the user does not confirm the submission of their exam ==>
==> the exam may be half filled ==> the answers displayed will be those selected by the user. */
Print->PrintedQuestions[NumQst].StrAnswers[0] = '\0';
/* Begin row for this question */
HTM_TR_Begin (NULL);
/* Title */
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
HTM_TxtF ("Pregunta %ld",QstCod);
HTM_TD_End ();
/* Number of questions to appear in exam print */
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
HTM_Txt ("Enunciado y respuestas");
HTM_TD_End ();
/* End title for this question */
HTM_TR_End ();
}
}

View File

@ -103,7 +103,7 @@ static void ExaRes_ShowEvtResultsSummaryRow (unsigned NumResults,
double TotalScoreOfAllResults, double TotalScoreOfAllResults,
double TotalGrade); double TotalGrade);
static void ExaRes_GetEventResultDataByEvtCod (long EvtCod,long UsrCod, static void ExaRes_GetEventResultDataByEvtCod (long EvtCod,long UsrCod,
struct TstRes_Result *Result); struct TstPrn_Print *Print);
static bool ExaRes_CheckIfICanSeeEventResult (struct ExaEvt_Event *Event,long UsrCod); static bool ExaRes_CheckIfICanSeeEventResult (struct ExaEvt_Event *Event,long UsrCod);
static bool ExaRes_CheckIfICanViewScore (bool ICanViewResult,unsigned Visibility); static bool ExaRes_CheckIfICanViewScore (bool ICanViewResult,unsigned Visibility);
@ -958,8 +958,8 @@ static void ExaRes_ShowEvtResults (struct Exa_Exams *Exams,
HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd);
if (ICanViewScore) if (ICanViewScore)
{ {
Grade = TstRes_ComputeGrade (NumQstsInThisResult,ScoreInThisResult,MaxGrade); Grade = TstPrn_ComputeGrade (NumQstsInThisResult,ScoreInThisResult,MaxGrade);
TstRes_ShowGrade (Grade,MaxGrade); TstPrn_ShowGrade (Grade,MaxGrade);
TotalGrade += Grade; TotalGrade += Grade;
} }
else else
@ -1092,7 +1092,7 @@ void ExaRes_ShowOneExaResult (void)
struct UsrData *UsrDat; struct UsrData *UsrDat;
Dat_StartEndTime_t StartEndTime; Dat_StartEndTime_t StartEndTime;
char *Id; char *Id;
struct TstRes_Result Result; struct TstPrn_Print Print;
bool ShowPhoto; bool ShowPhoto;
char PhotoURL[PATH_MAX + 1]; char PhotoURL[PATH_MAX + 1];
bool ICanViewResult; bool ICanViewResult;
@ -1122,8 +1122,8 @@ void ExaRes_ShowOneExaResult (void)
} }
/***** Get event result data *****/ /***** Get event result data *****/
TstRes_ResetResult (&Result); TstPrn_ResetResult (&Print);
ExaRes_GetEventResultDataByEvtCod (Event.EvtCod,UsrDat->UsrCod,&Result); ExaRes_GetEventResultDataByEvtCod (Event.EvtCod,UsrDat->UsrCod,&Print);
/***** Check if I can view this event result *****/ /***** Check if I can view this event result *****/
switch (Gbl.Usrs.Me.Role.Logged) switch (Gbl.Usrs.Me.Role.Logged)
@ -1154,7 +1154,7 @@ void ExaRes_ShowOneExaResult (void)
{ {
/***** Get questions and user's answers of the event result from database *****/ /***** Get questions and user's answers of the event result from database *****/
ExaRes_GetExamResultQuestionsFromDB (Event.EvtCod,UsrDat->UsrCod, ExaRes_GetExamResultQuestionsFromDB (Event.EvtCod,UsrDat->UsrCod,
&Result); &Print);
/***** Begin box *****/ /***** Begin box *****/
Box_BoxBegin (NULL,Event.Title, Box_BoxBegin (NULL,Event.Title,
@ -1230,8 +1230,8 @@ void ExaRes_ShowOneExaResult (void)
HTM_TD_Begin ("class=\"DAT LT\""); HTM_TD_Begin ("class=\"DAT LT\"");
HTM_TxtF ("%u (%u %s)", HTM_TxtF ("%u (%u %s)",
Result.NumQsts, Print.NumQsts,
Result.NumQstsNotBlank,Txt_non_blank_QUESTIONS); Print.NumQstsNotBlank,Txt_non_blank_QUESTIONS);
HTM_TD_End (); HTM_TD_End ();
HTM_TR_End (); HTM_TR_End ();
@ -1245,7 +1245,7 @@ void ExaRes_ShowOneExaResult (void)
HTM_TD_Begin ("class=\"DAT LT\""); HTM_TD_Begin ("class=\"DAT LT\"");
if (ICanViewScore) if (ICanViewScore)
HTM_Double2Decimals (Result.Score); HTM_Double2Decimals (Print.Score);
else else
Ico_PutIconNotVisible (); Ico_PutIconNotVisible ();
HTM_TD_End (); HTM_TD_End ();
@ -1261,7 +1261,7 @@ void ExaRes_ShowOneExaResult (void)
HTM_TD_Begin ("class=\"DAT LT\""); HTM_TD_Begin ("class=\"DAT LT\"");
if (ICanViewScore) if (ICanViewScore)
TstRes_ComputeAndShowGrade (Result.NumQsts,Result.Score, TstPrn_ComputeAndShowGrade (Print.NumQsts,Print.Score,
Exam.MaxGrade); Exam.MaxGrade);
else else
Ico_PutIconNotVisible (); Ico_PutIconNotVisible ();
@ -1283,7 +1283,7 @@ void ExaRes_ShowOneExaResult (void)
HTM_TR_End (); HTM_TR_End ();
/***** Write answers and solutions *****/ /***** Write answers and solutions *****/
TstRes_ShowExamAnswers (UsrDat,&Result,Exam.Visibility); TstPrn_ShowExamAnswers (UsrDat,&Print,Exam.Visibility);
/***** End table *****/ /***** End table *****/
HTM_TABLE_End (); HTM_TABLE_End ();
@ -1293,10 +1293,10 @@ void ExaRes_ShowOneExaResult (void)
{ {
HTM_DIV_Begin ("class=\"DAT_N_BOLD CM\""); HTM_DIV_Begin ("class=\"DAT_N_BOLD CM\"");
HTM_TxtColonNBSP (Txt_Score); HTM_TxtColonNBSP (Txt_Score);
HTM_Double2Decimals (Result.Score); HTM_Double2Decimals (Print.Score);
HTM_BR (); HTM_BR ();
HTM_TxtColonNBSP (Txt_Grade); HTM_TxtColonNBSP (Txt_Grade);
TstRes_ComputeAndShowGrade (Result.NumQsts,Result.Score, TstPrn_ComputeAndShowGrade (Print.NumQsts,Print.Score,
Exam.MaxGrade); Exam.MaxGrade);
HTM_DIV_End (); HTM_DIV_End ();
} }
@ -1313,7 +1313,7 @@ void ExaRes_ShowOneExaResult (void)
/*****************************************************************************/ /*****************************************************************************/
void ExaRes_GetExamResultQuestionsFromDB (long EvtCod,long UsrCod, void ExaRes_GetExamResultQuestionsFromDB (long EvtCod,long UsrCod,
struct TstRes_Result *Result) struct TstPrn_Print *Print)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
@ -1323,27 +1323,27 @@ void ExaRes_GetExamResultQuestionsFromDB (long EvtCod,long UsrCod,
struct ExaEvt_UsrAnswer UsrAnswer; struct ExaEvt_UsrAnswer UsrAnswer;
/***** Get questions and answers of a event result *****/ /***** Get questions and answers of a event result *****/
Result->NumQsts = (unsigned) Print->NumQsts = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get questions and answers" DB_QuerySELECT (&mysql_res,"can not get questions and answers"
" of a event result", " of a event result",
"SELECT exa_questions.QstCod," // row[0] "SELECT exa_questions.QstCod," // row[0]
"exa_questions.QstInd," // row[1] "exa_questions.QstInd," // row[1]
"exa_indexes.Indexes" // row[2] "exa_indexes.Indexes" // row[2]
" FROM exa_events,exa_questions,exa_indexes" " FROM exa_events,exa_questions,exa_indexes"
" WHERE exa_events.EvtCod=%ld" " WHERE exa_events.EvtCod=%ld"
" AND exa_events.ExaCod=exa_questions.ExaCod" " AND exa_events.ExaCod=exa_questions.ExaCod"
" AND exa_events.EvtCod=exa_indexes.EvtCod" " AND exa_events.EvtCod=exa_indexes.EvtCod"
" AND exa_questions.QstInd=exa_indexes.QstInd" " AND exa_questions.QstInd=exa_indexes.QstInd"
" ORDER BY exa_questions.QstInd", " ORDER BY exa_questions.QstInd",
EvtCod); EvtCod);
for (NumQst = 0, Result->NumQstsNotBlank = 0; for (NumQst = 0, Print->NumQstsNotBlank = 0;
NumQst < Result->NumQsts; NumQst < Print->NumQsts;
NumQst++) NumQst++)
{ {
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/* Get question code (row[0]) */ /* Get question code (row[0]) */
if ((Result->Questions[NumQst].QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) if ((Print->PrintedQuestions[NumQst].QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of question."); Lay_ShowErrorAndExit ("Wrong code of question.");
/* Get question index (row[1]) */ /* Get question index (row[1]) */
@ -1352,24 +1352,24 @@ void ExaRes_GetExamResultQuestionsFromDB (long EvtCod,long UsrCod,
QstInd = (unsigned) LongNum; QstInd = (unsigned) LongNum;
/* Get indexes for this question (row[2]) */ /* Get indexes for this question (row[2]) */
Str_Copy (Result->Questions[NumQst].StrIndexes,row[2], Str_Copy (Print->PrintedQuestions[NumQst].StrIndexes,row[2],
TstRes_MAX_BYTES_INDEXES_ONE_QST); TstPrn_MAX_BYTES_INDEXES_ONE_QST);
/* Get answers selected by user for this question */ /* Get answers selected by user for this question */
ExaEvt_GetQstAnsFromDB (EvtCod,UsrCod,QstInd,&UsrAnswer); ExaEvt_GetQstAnsFromDB (EvtCod,UsrCod,QstInd,&UsrAnswer);
if (UsrAnswer.AnsInd >= 0) // UsrAnswer.AnsInd >= 0 ==> answer selected if (UsrAnswer.AnsInd >= 0) // UsrAnswer.AnsInd >= 0 ==> answer selected
{ {
snprintf (Result->Questions[NumQst].StrAnswers,TstRes_MAX_BYTES_ANSWERS_ONE_QST + 1, snprintf (Print->PrintedQuestions[NumQst].StrAnswers,TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1,
"%d",UsrAnswer.AnsInd); "%d",UsrAnswer.AnsInd);
Result->NumQstsNotBlank++; Print->NumQstsNotBlank++;
} }
else // UsrAnswer.AnsInd < 0 ==> no answer selected else // UsrAnswer.AnsInd < 0 ==> no answer selected
Result->Questions[NumQst].StrAnswers[0] = '\0'; // Empty answer Print->PrintedQuestions[NumQst].StrAnswers[0] = '\0'; // Empty answer
/* Replace each comma by a separator of multiple parameters */ /* Replace each comma by a separator of multiple parameters */
/* In database commas are used as separators instead of special chars */ /* In database commas are used as separators instead of special chars */
Par_ReplaceCommaBySeparatorMultiple (Result->Questions[NumQst].StrIndexes); Par_ReplaceCommaBySeparatorMultiple (Print->PrintedQuestions[NumQst].StrIndexes);
Par_ReplaceCommaBySeparatorMultiple (Result->Questions[NumQst].StrAnswers); Par_ReplaceCommaBySeparatorMultiple (Print->PrintedQuestions[NumQst].StrAnswers);
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
@ -1381,7 +1381,7 @@ void ExaRes_GetExamResultQuestionsFromDB (long EvtCod,long UsrCod,
/*****************************************************************************/ /*****************************************************************************/
static void ExaRes_GetEventResultDataByEvtCod (long EvtCod,long UsrCod, static void ExaRes_GetEventResultDataByEvtCod (long EvtCod,long UsrCod,
struct TstRes_Result *Result) struct TstPrn_Print *Print)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
@ -1410,27 +1410,27 @@ static void ExaRes_GetEventResultDataByEvtCod (long EvtCod,long UsrCod,
for (StartEndTime = (Dat_StartEndTime_t) 0; for (StartEndTime = (Dat_StartEndTime_t) 0;
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1); StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
StartEndTime++) StartEndTime++)
Result->TimeUTC[StartEndTime] = Dat_GetUNIXTimeFromStr (row[StartEndTime]); Print->TimeUTC[StartEndTime] = Dat_GetUNIXTimeFromStr (row[StartEndTime]);
/* Get number of questions (row[2]) */ /* Get number of questions (row[2]) */
if (sscanf (row[2],"%u",&Result->NumQsts) != 1) if (sscanf (row[2],"%u",&Print->NumQsts) != 1)
Result->NumQsts = 0; Print->NumQsts = 0;
/* Get number of questions not blank (row[3]) */ /* Get number of questions not blank (row[3]) */
if (sscanf (row[3],"%u",&Result->NumQstsNotBlank) != 1) if (sscanf (row[3],"%u",&Print->NumQstsNotBlank) != 1)
Result->NumQstsNotBlank = 0; Print->NumQstsNotBlank = 0;
/* Get score (row[4]) */ /* Get score (row[4]) */
Str_SetDecimalPointToUS (); // To get the decimal point as a dot Str_SetDecimalPointToUS (); // To get the decimal point as a dot
if (sscanf (row[4],"%lf",&Result->Score) != 1) if (sscanf (row[4],"%lf",&Print->Score) != 1)
Result->Score = 0.0; Print->Score = 0.0;
Str_SetDecimalPointToLocal (); // Return to local system Str_SetDecimalPointToLocal (); // Return to local system
} }
else else
{ {
Result->NumQsts = 0; Print->NumQsts = 0;
Result->NumQstsNotBlank = 0; Print->NumQstsNotBlank = 0;
Result->Score = 0.0; Print->Score = 0.0;
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/

View File

@ -27,7 +27,7 @@
/********************************* Headers ***********************************/ /********************************* Headers ***********************************/
/*****************************************************************************/ /*****************************************************************************/
#include "swad_test_exam.h" #include "swad_test_print.h"
/*****************************************************************************/ /*****************************************************************************/
/************************** Public types and constants ***********************/ /************************** Public types and constants ***********************/
@ -51,6 +51,6 @@ void ExaRes_ShowAllExaResultsInEvt (void);
void ExaRes_ShowOneExaResult (void); void ExaRes_ShowOneExaResult (void);
void ExaRes_GetExamResultQuestionsFromDB (long EvtCod,long UsrCod, void ExaRes_GetExamResultQuestionsFromDB (long EvtCod,long UsrCod,
struct TstRes_Result *Result); struct TstPrn_Print *Print);
#endif #endif

View File

@ -229,7 +229,7 @@ static void Mch_GetNumPlayers (struct Mch_Match *Match);
static void Mch_RemoveMyAnswerToMatchQuestion (const struct Mch_Match *Match); static void Mch_RemoveMyAnswerToMatchQuestion (const struct Mch_Match *Match);
static void Mch_ComputeScore (struct TstRes_Result *Result); static void Mch_ComputeScore (struct TstPrn_Print *Print);
static unsigned Mch_GetNumUsrsWhoHaveAnswerMch (long MchCod); static unsigned Mch_GetNumUsrsWhoHaveAnswerMch (long MchCod);
@ -1612,7 +1612,7 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
long LongNum; long LongNum;
unsigned AnsInd; unsigned AnsInd;
char StrOneAnswer[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; char StrOneAnswer[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
char StrAnswersOneQst[TstRes_MAX_BYTES_ANSWERS_ONE_QST + 1]; char StrAnswersOneQst[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1];
/***** Initialize list of answers to empty string *****/ /***** Initialize list of answers to empty string *****/
StrAnswersOneQst[0] = '\0'; StrAnswersOneQst[0] = '\0';
@ -1645,9 +1645,9 @@ static void Mch_ReorderAnswer (long MchCod,unsigned QstInd,
/* Concatenate answer index to list of answers */ /* Concatenate answer index to list of answers */
if (NumAns) if (NumAns)
Str_Concat (StrAnswersOneQst,",", Str_Concat (StrAnswersOneQst,",",
TstRes_MAX_BYTES_ANSWERS_ONE_QST); TstPrn_MAX_BYTES_ANSWERS_ONE_QST);
Str_Concat (StrAnswersOneQst,StrOneAnswer, Str_Concat (StrAnswersOneQst,StrOneAnswer,
TstRes_MAX_BYTES_ANSWERS_ONE_QST); TstPrn_MAX_BYTES_ANSWERS_ONE_QST);
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
@ -1671,7 +1671,7 @@ void Mch_GetIndexes (long MchCod,unsigned QstInd,
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
char StrIndexesOneQst[TstRes_MAX_BYTES_INDEXES_ONE_QST + 1]; char StrIndexesOneQst[TstPrn_MAX_BYTES_INDEXES_ONE_QST + 1];
/***** Get indexes for a question from database *****/ /***** Get indexes for a question from database *****/
if (!DB_QuerySELECT (&mysql_res,"can not get data of a question", if (!DB_QuerySELECT (&mysql_res,"can not get data of a question",
@ -1684,14 +1684,14 @@ void Mch_GetIndexes (long MchCod,unsigned QstInd,
/* Get indexes (row[0]) */ /* Get indexes (row[0]) */
Str_Copy (StrIndexesOneQst,row[0], Str_Copy (StrIndexesOneQst,row[0],
TstRes_MAX_BYTES_INDEXES_ONE_QST); TstPrn_MAX_BYTES_INDEXES_ONE_QST);
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res); DB_FreeMySQLResult (&mysql_res);
/***** Get indexes from string *****/ /***** Get indexes from string *****/
Par_ReplaceCommaBySeparatorMultiple (StrIndexesOneQst); Par_ReplaceCommaBySeparatorMultiple (StrIndexesOneQst);
TstRes_GetIndexesFromStr (StrIndexesOneQst,Indexes); TstPrn_GetIndexesFromStr (StrIndexesOneQst,Indexes);
} }
/*****************************************************************************/ /*****************************************************************************/
@ -3881,7 +3881,7 @@ void Mch_ReceiveQuestionAnswer (void)
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]; unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION];
struct Mch_UsrAnswer PreviousUsrAnswer; struct Mch_UsrAnswer PreviousUsrAnswer;
struct Mch_UsrAnswer UsrAnswer; struct Mch_UsrAnswer UsrAnswer;
struct TstRes_Result Result; struct TstPrn_Print Print;
/***** Reset match *****/ /***** Reset match *****/
Mch_ResetMatch (&Match); Mch_ResetMatch (&Match);
@ -3940,14 +3940,14 @@ void Mch_ReceiveQuestionAnswer (void)
/***** Update student's match result *****/ /***** Update student's match result *****/
MchRes_GetMatchResultQuestionsFromDB (Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod, MchRes_GetMatchResultQuestionsFromDB (Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,
&Result); &Print);
Mch_ComputeScore (&Result); Mch_ComputeScore (&Print);
Str_SetDecimalPointToUS (); // To print the floating point as a dot Str_SetDecimalPointToUS (); // To print the floating point as a dot
if (DB_QueryCOUNT ("can not get if match result exists", if (DB_QueryCOUNT ("can not get if match result exists",
"SELECT COUNT(*) FROM mch_results" "SELECT COUNT(*) FROM mch_results"
" WHERE MchCod=%ld AND UsrCod=%ld", " WHERE MchCod=%ld AND UsrCod=%ld",
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod)) // Result exists Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod)) // Match print exists
/* Update result */ /* Update result */
DB_QueryUPDATE ("can not update match result", DB_QueryUPDATE ("can not update match result",
"UPDATE mch_results" "UPDATE mch_results"
@ -3956,11 +3956,11 @@ void Mch_ReceiveQuestionAnswer (void)
"NumQstsNotBlank=%u," "NumQstsNotBlank=%u,"
"Score='%.15lg'" "Score='%.15lg'"
" WHERE MchCod=%ld AND UsrCod=%ld", " WHERE MchCod=%ld AND UsrCod=%ld",
Result.NumQsts, Print.NumQsts,
Result.NumQstsNotBlank, Print.NumQstsNotBlank,
Result.Score, Print.Score,
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod); Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod);
else // Result doesn't exist else // Match print doesn't exist
/* Create result */ /* Create result */
DB_QueryINSERT ("can not create match result", DB_QueryINSERT ("can not create match result",
"INSERT mch_results " "INSERT mch_results "
@ -3974,9 +3974,9 @@ void Mch_ReceiveQuestionAnswer (void)
"%u," // NumQstsNotBlank "%u," // NumQstsNotBlank
"'%.15lg')", // Score "'%.15lg')", // Score
Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod, Match.MchCod,Gbl.Usrs.Me.UsrDat.UsrCod,
Result.NumQsts, Print.NumQsts,
Result.NumQstsNotBlank, Print.NumQstsNotBlank,
Result.Score); Print.Score);
Str_SetDecimalPointToLocal (); // Return to local system Str_SetDecimalPointToLocal (); // Return to local system
} }
@ -4002,25 +4002,25 @@ static void Mch_RemoveMyAnswerToMatchQuestion (const struct Mch_Match *Match)
/******************** Compute match score for a student **********************/ /******************** Compute match score for a student **********************/
/*****************************************************************************/ /*****************************************************************************/
static void Mch_ComputeScore (struct TstRes_Result *Result) static void Mch_ComputeScore (struct TstPrn_Print *Print)
{ {
unsigned NumQst; unsigned NumQst;
struct Tst_Question Question; struct Tst_Question Question;
for (NumQst = 0, Result->Score = 0.0; for (NumQst = 0, Print->Score = 0.0;
NumQst < Result->NumQsts; NumQst < Print->NumQsts;
NumQst++) NumQst++)
{ {
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question); Tst_QstConstructor (&Question);
Question.QstCod = Result->Questions[NumQst].QstCod; Question.QstCod = Print->PrintedQuestions[NumQst].QstCod;
Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE; Question.Answer.Type = Tst_ANS_UNIQUE_CHOICE;
/***** Compute score for this answer ******/ /***** Compute score for this answer ******/
TstRes_ComputeChoiceAnsScore (Result,NumQst,&Question); TstPrn_ComputeChoiceAnsScore (Print,NumQst,&Question);
/***** Update total score *****/ /***** Update total score *****/
Result->Score += Result->Questions[NumQst].Score; Print->Score += Print->PrintedQuestions[NumQst].Score;
/***** Destroy test question *****/ /***** Destroy test question *****/
Tst_QstDestructor (&Question); Tst_QstDestructor (&Question);

View File

@ -101,7 +101,7 @@ static void MchRes_ShowMchResultsSummaryRow (unsigned NumResults,
double TotalScoreOfAllResults, double TotalScoreOfAllResults,
double TotalGrade); double TotalGrade);
static void MchRes_GetMatchResultDataByMchCod (long MchCod,long UsrCod, static void MchRes_GetMatchResultDataByMchCod (long MchCod,long UsrCod,
struct TstRes_Result *Result); struct TstPrn_Print *Print);
static bool MchRes_CheckIfICanSeeMatchResult (struct Mch_Match *Match,long UsrCod); static bool MchRes_CheckIfICanSeeMatchResult (struct Mch_Match *Match,long UsrCod);
static bool MchRes_CheckIfICanViewScore (bool ICanViewResult,unsigned Visibility); static bool MchRes_CheckIfICanViewScore (bool ICanViewResult,unsigned Visibility);
@ -947,8 +947,8 @@ static void MchRes_ShowMchResults (struct Gam_Games *Games,
HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd); HTM_TD_Begin ("class=\"DAT RT COLOR%u\"",Gbl.RowEvenOdd);
if (ICanViewScore) if (ICanViewScore)
{ {
Grade = TstRes_ComputeGrade (NumQstsInThisResult,ScoreInThisResult,MaxGrade); Grade = TstPrn_ComputeGrade (NumQstsInThisResult,ScoreInThisResult,MaxGrade);
TstRes_ShowGrade (Grade,MaxGrade); TstPrn_ShowGrade (Grade,MaxGrade);
TotalGrade += Grade; TotalGrade += Grade;
} }
else else
@ -1081,7 +1081,7 @@ void MchRes_ShowOneMchResult (void)
struct UsrData *UsrDat; struct UsrData *UsrDat;
Dat_StartEndTime_t StartEndTime; Dat_StartEndTime_t StartEndTime;
char *Id; char *Id;
struct TstRes_Result Result; struct TstPrn_Print Print;
bool ShowPhoto; bool ShowPhoto;
char PhotoURL[PATH_MAX + 1]; char PhotoURL[PATH_MAX + 1];
bool ICanViewResult; bool ICanViewResult;
@ -1113,8 +1113,8 @@ void MchRes_ShowOneMchResult (void)
} }
/***** Get match result data *****/ /***** Get match result data *****/
TstRes_ResetResult (&Result); TstPrn_ResetResult (&Print);
MchRes_GetMatchResultDataByMchCod (Match.MchCod,UsrDat->UsrCod,&Result); MchRes_GetMatchResultDataByMchCod (Match.MchCod,UsrDat->UsrCod,&Print);
/***** Check if I can view this match result *****/ /***** Check if I can view this match result *****/
switch (Gbl.Usrs.Me.Role.Logged) switch (Gbl.Usrs.Me.Role.Logged)
@ -1145,7 +1145,7 @@ void MchRes_ShowOneMchResult (void)
{ {
/***** Get questions and user's answers of the match result from database *****/ /***** Get questions and user's answers of the match result from database *****/
MchRes_GetMatchResultQuestionsFromDB (Match.MchCod,UsrDat->UsrCod, MchRes_GetMatchResultQuestionsFromDB (Match.MchCod,UsrDat->UsrCod,
&Result); &Print);
/***** Begin box *****/ /***** Begin box *****/
Box_BoxBegin (NULL,Match.Title, Box_BoxBegin (NULL,Match.Title,
@ -1203,7 +1203,7 @@ void MchRes_ShowOneMchResult (void)
if (asprintf (&Id,"match_%u",(unsigned) StartEndTime) < 0) if (asprintf (&Id,"match_%u",(unsigned) StartEndTime) < 0)
Lay_NotEnoughMemoryExit (); Lay_NotEnoughMemoryExit ();
HTM_TD_Begin ("id=\"%s\" class=\"DAT LT\"",Id); HTM_TD_Begin ("id=\"%s\" class=\"DAT LT\"",Id);
Dat_WriteLocalDateHMSFromUTC (Id,Result.TimeUTC[StartEndTime], Dat_WriteLocalDateHMSFromUTC (Id,Print.TimeUTC[StartEndTime],
Gbl.Prefs.DateFormat,Dat_SEPARATOR_COMMA, Gbl.Prefs.DateFormat,Dat_SEPARATOR_COMMA,
true,true,true,0x7); true,true,true,0x7);
HTM_TD_End (); HTM_TD_End ();
@ -1221,8 +1221,8 @@ void MchRes_ShowOneMchResult (void)
HTM_TD_Begin ("class=\"DAT LT\""); HTM_TD_Begin ("class=\"DAT LT\"");
HTM_TxtF ("%u (%u %s)", HTM_TxtF ("%u (%u %s)",
Result.NumQsts, Print.NumQsts,
Result.NumQstsNotBlank,Txt_non_blank_QUESTIONS); Print.NumQstsNotBlank,Txt_non_blank_QUESTIONS);
HTM_TD_End (); HTM_TD_End ();
HTM_TR_End (); HTM_TR_End ();
@ -1236,7 +1236,7 @@ void MchRes_ShowOneMchResult (void)
HTM_TD_Begin ("class=\"DAT LT\""); HTM_TD_Begin ("class=\"DAT LT\"");
if (ICanViewScore) if (ICanViewScore)
HTM_Double2Decimals (Result.Score); HTM_Double2Decimals (Print.Score);
else else
Ico_PutIconNotVisible (); Ico_PutIconNotVisible ();
HTM_TD_End (); HTM_TD_End ();
@ -1252,7 +1252,7 @@ void MchRes_ShowOneMchResult (void)
HTM_TD_Begin ("class=\"DAT LT\""); HTM_TD_Begin ("class=\"DAT LT\"");
if (ICanViewScore) if (ICanViewScore)
TstRes_ComputeAndShowGrade (Result.NumQsts,Result.Score, TstPrn_ComputeAndShowGrade (Print.NumQsts,Print.Score,
Game.MaxGrade); Game.MaxGrade);
else else
Ico_PutIconNotVisible (); Ico_PutIconNotVisible ();
@ -1274,7 +1274,7 @@ void MchRes_ShowOneMchResult (void)
HTM_TR_End (); HTM_TR_End ();
/***** Write answers and solutions *****/ /***** Write answers and solutions *****/
TstRes_ShowExamAnswers (UsrDat,&Result,Game.Visibility); TstPrn_ShowExamAnswers (UsrDat,&Print,Game.Visibility);
/***** End table *****/ /***** End table *****/
HTM_TABLE_End (); HTM_TABLE_End ();
@ -1284,10 +1284,10 @@ void MchRes_ShowOneMchResult (void)
{ {
HTM_DIV_Begin ("class=\"DAT_N_BOLD CM\""); HTM_DIV_Begin ("class=\"DAT_N_BOLD CM\"");
HTM_TxtColonNBSP (Txt_Score); HTM_TxtColonNBSP (Txt_Score);
HTM_Double2Decimals (Result.Score); HTM_Double2Decimals (Print.Score);
HTM_BR (); HTM_BR ();
HTM_TxtColonNBSP (Txt_Grade); HTM_TxtColonNBSP (Txt_Grade);
TstRes_ComputeAndShowGrade (Result.NumQsts,Result.Score, TstPrn_ComputeAndShowGrade (Print.NumQsts,Print.Score,
Game.MaxGrade); Game.MaxGrade);
HTM_DIV_End (); HTM_DIV_End ();
} }
@ -1304,7 +1304,7 @@ void MchRes_ShowOneMchResult (void)
/*****************************************************************************/ /*****************************************************************************/
void MchRes_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod, void MchRes_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod,
struct TstRes_Result *Result) struct TstPrn_Print *Print)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
@ -1314,27 +1314,27 @@ void MchRes_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod,
struct Mch_UsrAnswer UsrAnswer; struct Mch_UsrAnswer UsrAnswer;
/***** Get questions and answers of a match result *****/ /***** Get questions and answers of a match result *****/
Result->NumQsts = (unsigned) Print->NumQsts = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get questions and answers" DB_QuerySELECT (&mysql_res,"can not get questions and answers"
" of a match result", " of a match result",
"SELECT gam_questions.QstCod," // row[0] "SELECT gam_questions.QstCod," // row[0]
"gam_questions.QstInd," // row[1] "gam_questions.QstInd," // row[1]
"mch_indexes.Indexes" // row[2] "mch_indexes.Indexes" // row[2]
" FROM mch_matches,gam_questions,mch_indexes" " FROM mch_matches,gam_questions,mch_indexes"
" WHERE mch_matches.MchCod=%ld" " WHERE mch_matches.MchCod=%ld"
" AND mch_matches.GamCod=gam_questions.GamCod" " AND mch_matches.GamCod=gam_questions.GamCod"
" AND mch_matches.MchCod=mch_indexes.MchCod" " AND mch_matches.MchCod=mch_indexes.MchCod"
" AND gam_questions.QstInd=mch_indexes.QstInd" " AND gam_questions.QstInd=mch_indexes.QstInd"
" ORDER BY gam_questions.QstInd", " ORDER BY gam_questions.QstInd",
MchCod); MchCod);
for (NumQst = 0, Result->NumQstsNotBlank = 0; for (NumQst = 0, Print->NumQstsNotBlank = 0;
NumQst < Result->NumQsts; NumQst < Print->NumQsts;
NumQst++) NumQst++)
{ {
row = mysql_fetch_row (mysql_res); row = mysql_fetch_row (mysql_res);
/* Get question code (row[0]) */ /* Get question code (row[0]) */
if ((Result->Questions[NumQst].QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) if ((Print->PrintedQuestions[NumQst].QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of question."); Lay_ShowErrorAndExit ("Wrong code of question.");
/* Get question index (row[1]) */ /* Get question index (row[1]) */
@ -1343,24 +1343,24 @@ void MchRes_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod,
QstInd = (unsigned) LongNum; QstInd = (unsigned) LongNum;
/* Get indexes for this question (row[2]) */ /* Get indexes for this question (row[2]) */
Str_Copy (Result->Questions[NumQst].StrIndexes,row[2], Str_Copy (Print->PrintedQuestions[NumQst].StrIndexes,row[2],
TstRes_MAX_BYTES_INDEXES_ONE_QST); TstPrn_MAX_BYTES_INDEXES_ONE_QST);
/* Get answers selected by user for this question */ /* Get answers selected by user for this question */
Mch_GetQstAnsFromDB (MchCod,UsrCod,QstInd,&UsrAnswer); Mch_GetQstAnsFromDB (MchCod,UsrCod,QstInd,&UsrAnswer);
if (UsrAnswer.AnsInd >= 0) // UsrAnswer.AnsInd >= 0 ==> answer selected if (UsrAnswer.AnsInd >= 0) // UsrAnswer.AnsInd >= 0 ==> answer selected
{ {
snprintf (Result->Questions[NumQst].StrAnswers,TstRes_MAX_BYTES_ANSWERS_ONE_QST + 1, snprintf (Print->PrintedQuestions[NumQst].StrAnswers,TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1,
"%d",UsrAnswer.AnsInd); "%d",UsrAnswer.AnsInd);
Result->NumQstsNotBlank++; Print->NumQstsNotBlank++;
} }
else // UsrAnswer.AnsInd < 0 ==> no answer selected else // UsrAnswer.AnsInd < 0 ==> no answer selected
Result->Questions[NumQst].StrAnswers[0] = '\0'; // Empty answer Print->PrintedQuestions[NumQst].StrAnswers[0] = '\0'; // Empty answer
/* Replace each comma by a separator of multiple parameters */ /* Replace each comma by a separator of multiple parameters */
/* In database commas are used as separators instead of special chars */ /* In database commas are used as separators instead of special chars */
Par_ReplaceCommaBySeparatorMultiple (Result->Questions[NumQst].StrIndexes); Par_ReplaceCommaBySeparatorMultiple (Print->PrintedQuestions[NumQst].StrIndexes);
Par_ReplaceCommaBySeparatorMultiple (Result->Questions[NumQst].StrAnswers); Par_ReplaceCommaBySeparatorMultiple (Print->PrintedQuestions[NumQst].StrAnswers);
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
@ -1372,7 +1372,7 @@ void MchRes_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod,
/*****************************************************************************/ /*****************************************************************************/
static void MchRes_GetMatchResultDataByMchCod (long MchCod,long UsrCod, static void MchRes_GetMatchResultDataByMchCod (long MchCod,long UsrCod,
struct TstRes_Result *Result) struct TstPrn_Print *Print)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
@ -1401,27 +1401,27 @@ static void MchRes_GetMatchResultDataByMchCod (long MchCod,long UsrCod,
for (StartEndTime = (Dat_StartEndTime_t) 0; for (StartEndTime = (Dat_StartEndTime_t) 0;
StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1); StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1);
StartEndTime++) StartEndTime++)
Result->TimeUTC[StartEndTime] = Dat_GetUNIXTimeFromStr (row[StartEndTime]); Print->TimeUTC[StartEndTime] = Dat_GetUNIXTimeFromStr (row[StartEndTime]);
/* Get number of questions (row[2]) */ /* Get number of questions (row[2]) */
if (sscanf (row[2],"%u",&Result->NumQsts) != 1) if (sscanf (row[2],"%u",&Print->NumQsts) != 1)
Result->NumQsts = 0; Print->NumQsts = 0;
/* Get number of questions not blank (row[3]) */ /* Get number of questions not blank (row[3]) */
if (sscanf (row[3],"%u",&Result->NumQstsNotBlank) != 1) if (sscanf (row[3],"%u",&Print->NumQstsNotBlank) != 1)
Result->NumQstsNotBlank = 0; Print->NumQstsNotBlank = 0;
/* Get score (row[4]) */ /* Get score (row[4]) */
Str_SetDecimalPointToUS (); // To get the decimal point as a dot Str_SetDecimalPointToUS (); // To get the decimal point as a dot
if (sscanf (row[4],"%lf",&Result->Score) != 1) if (sscanf (row[4],"%lf",&Print->Score) != 1)
Result->Score = 0.0; Print->Score = 0.0;
Str_SetDecimalPointToLocal (); // Return to local system Str_SetDecimalPointToLocal (); // Return to local system
} }
else else
{ {
Result->NumQsts = 0; Print->NumQsts = 0;
Result->NumQstsNotBlank = 0; Print->NumQstsNotBlank = 0;
Result->Score = 0.0; Print->Score = 0.0;
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/

View File

@ -27,7 +27,7 @@
/********************************* Headers ***********************************/ /********************************* Headers ***********************************/
/*****************************************************************************/ /*****************************************************************************/
#include "swad_test_exam.h" #include "swad_test_print.h"
/*****************************************************************************/ /*****************************************************************************/
/************************** Public types and constants ***********************/ /************************** Public types and constants ***********************/
@ -51,6 +51,6 @@ void MchRes_ShowAllMchResultsInMch (void);
void MchRes_ShowOneMchResult (void); void MchRes_ShowOneMchResult (void);
void MchRes_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod, void MchRes_GetMatchResultQuestionsFromDB (long MchCod,long UsrCod,
struct TstRes_Result *Result); struct TstPrn_Print *Print);
#endif #endif

View File

@ -52,9 +52,9 @@
#include "swad_parameter.h" #include "swad_parameter.h"
#include "swad_theme.h" #include "swad_theme.h"
#include "swad_test.h" #include "swad_test.h"
#include "swad_test_exam.h"
#include "swad_test_config.h" #include "swad_test_config.h"
#include "swad_test_import.h" #include "swad_test_import.h"
#include "swad_test_print.h"
#include "swad_test_visibility.h" #include "swad_test_visibility.h"
#include "swad_user.h" #include "swad_user.h"
#include "swad_xml.h" #include "swad_xml.h"
@ -133,15 +133,15 @@ static void Tst_ShowFormRequestTest (struct Tst_Test *Test);
static void Tst_PutCheckBoxAllowTeachers (bool AllowTeachers); static void Tst_PutCheckBoxAllowTeachers (bool AllowTeachers);
static void Tst_GetAnswersFromForm (struct TstRes_Result *Result); static void Tst_GetAnswersFromForm (struct TstPrn_Print *Print);
static bool Tst_CheckIfNextTstAllowed (void); static bool Tst_CheckIfNextTstAllowed (void);
static unsigned Tst_GetNumExamsGeneratedByMe (void); static unsigned Tst_GetNumExamsGeneratedByMe (void);
static void Tst_ShowTestExamToFillIt (struct TstRes_Result *Result, static void Tst_ShowTestExamToFillIt (struct TstPrn_Print *Print,
unsigned NumExamsGeneratedByMe, unsigned NumExamsGeneratedByMe,
Tst_RequestOrConfirm_t RequestOrConfirm); Tst_RequestOrConfirm_t RequestOrConfirm);
static void Tst_WriteQstAndAnsSeeing (const struct TstRes_Result *Result, static void Tst_WriteQstAndAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst, unsigned NumQst,
const struct Tst_Question *Question); const struct Tst_Question *Question);
@ -177,10 +177,7 @@ static void Tst_PutInputFieldNumQst (const char *Field,const char *Label,
static void Tst_ShowFormAnswerTypes (const struct Tst_AnswerTypes *AnswerTypes); static void Tst_ShowFormAnswerTypes (const struct Tst_AnswerTypes *AnswerTypes);
static void Tst_GetQuestions (struct Tst_Test *Test,MYSQL_RES **mysql_res); static void Tst_GetQuestions (struct Tst_Test *Test,MYSQL_RES **mysql_res);
static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test, static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test,
struct TstRes_Result *Result); struct TstPrn_Print *Print);
static void Tst_GenerateChoiceIndexesDependingOnShuffle (struct TstRes_Result *Result,
unsigned NumQst,
bool Shuffle);
static void Tst_ListOneQstToEdit (struct Tst_Test *Test); static void Tst_ListOneQstToEdit (struct Tst_Test *Test);
static void Tst_ListOneOrMoreQuestionsForEdition (struct Tst_Test *Test, static void Tst_ListOneOrMoreQuestionsForEdition (struct Tst_Test *Test,
@ -196,28 +193,28 @@ static void Tst_ListOneOrMoreQuestionsForSelectionForGame (struct Gam_Games *Gam
static void Tst_WriteQuestionRowForSelection (unsigned NumQst, static void Tst_WriteQuestionRowForSelection (unsigned NumQst,
struct Tst_Question *Question); struct Tst_Question *Question);
static void Tst_WriteAnswersSeeing (const struct TstRes_Result *Result, static void Tst_WriteAnswersSeeing (const struct TstPrn_Print *Print,
unsigned NumQst, unsigned NumQst,
const struct Tst_Question *Question); const struct Tst_Question *Question);
static void Tst_WriteIntAnsListing (const struct Tst_Question *Question); static void Tst_WriteIntAnsListing (const struct Tst_Question *Question);
static void Tst_WriteIntAnsSeeing (const struct TstRes_Result *Result, static void Tst_WriteIntAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst); unsigned NumQst);
static void Tst_WriteFloatAnsEdit (const struct Tst_Question *Question); static void Tst_WriteFloatAnsEdit (const struct Tst_Question *Question);
static void Tst_WriteFloatAnsSeeing (const struct TstRes_Result *Result, static void Tst_WriteFloatAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst); unsigned NumQst);
static void Tst_WriteTFAnsListing (const struct Tst_Question *Question); static void Tst_WriteTFAnsListing (const struct Tst_Question *Question);
static void Tst_WriteTFAnsSeeing (const struct TstRes_Result *Result, static void Tst_WriteTFAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst); unsigned NumQst);
static void Tst_WriteChoiceAnsListing (const struct Tst_Question *Question); static void Tst_WriteChoiceAnsListing (const struct Tst_Question *Question);
static void Tst_WriteChoiceAnsSeeing (const struct TstRes_Result *Result, static void Tst_WriteChoiceAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst, unsigned NumQst,
const struct Tst_Question *Question); const struct Tst_Question *Question);
static void Tst_WriteTextAnsSeeing (const struct TstRes_Result *Result, static void Tst_WriteTextAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst); unsigned NumQst);
static void Tst_WriteParamQstCod (unsigned NumQst,long QstCod); static void Tst_WriteParamQstCod (unsigned NumQst,long QstCod);
@ -446,7 +443,7 @@ void Tst_ShowNewTest (void)
{ {
extern const char *Txt_No_questions_found_matching_your_search_criteria; extern const char *Txt_No_questions_found_matching_your_search_criteria;
struct Tst_Test Test; struct Tst_Test Test;
struct TstRes_Result Exam; struct TstPrn_Print Print;
unsigned NumExamsGeneratedByMe; unsigned NumExamsGeneratedByMe;
/***** Create test *****/ /***** Create test *****/
@ -461,21 +458,21 @@ void Tst_ShowNewTest (void)
if (Tst_GetParamsTst (&Test,Tst_SHOW_TEST_TO_ANSWER)) // Get parameters from form if (Tst_GetParamsTst (&Test,Tst_SHOW_TEST_TO_ANSWER)) // Get parameters from form
{ {
/***** Get questions *****/ /***** Get questions *****/
TstRes_ResetResult (&Exam); TstPrn_ResetResult (&Print);
Tst_GetQuestionsForNewTestFromDB (&Test,&Exam); Tst_GetQuestionsForNewTestFromDB (&Test,&Print);
if (Exam.NumQsts) if (Print.NumQsts)
{ {
/***** Increase number of exams generated (answered or not) by me *****/ /***** Increase number of exams generated (answered or not) by me *****/
Tst_IncreaseMyNumAccessTst (); Tst_IncreaseMyNumAccessTst ();
NumExamsGeneratedByMe = Tst_GetNumExamsGeneratedByMe (); NumExamsGeneratedByMe = Tst_GetNumExamsGeneratedByMe ();
/***** Create new test exam in database *****/ /***** Create new test exam in database *****/
TstRes_CreateExamInDB (&Exam); TstPrn_CreateExamInDB (&Print);
TstRes_ComputeScoresAndStoreExamQuestions (&Exam, TstPrn_ComputeScoresAndStoreExamQuestions (&Print,
false); // Don't update question score false); // Don't update question score
/***** Show test exam to be answered *****/ /***** Show test exam to be answered *****/
Tst_ShowTestExamToFillIt (&Exam,NumExamsGeneratedByMe,Tst_REQUEST); Tst_ShowTestExamToFillIt (&Print,NumExamsGeneratedByMe,Tst_REQUEST);
/***** Update date-time of my next allowed access to test *****/ /***** Update date-time of my next allowed access to test *****/
if (Gbl.Usrs.Me.Role.Logged == Rol_STD) if (Gbl.Usrs.Me.Role.Logged == Rol_STD)
@ -523,47 +520,48 @@ static void Tst_PutCheckBoxAllowTeachers (bool AllowTeachers)
void Tst_ReceiveTestDraft (void) void Tst_ReceiveTestDraft (void)
{ {
extern const char *Txt_The_test_X_has_already_been_assessed_previously; extern const char *Txt_The_test_X_has_already_been_assessed_previously;
extern const char *Txt_Please_review_your_answers_before_submitting_the_exam;
unsigned NumTst; unsigned NumTst;
struct TstRes_Result Result; struct TstPrn_Print Print;
/***** Read test configuration from database *****/ /***** Read test configuration from database *****/
TstCfg_GetConfigFromDB (); TstCfg_GetConfigFromDB ();
/***** Get basic parameters of the exam *****/ /***** Get basic parameters of the exam *****/
/* Get test exam code from form */ /* Get test exam code from form */
TstRes_ResetResult (&Result); TstPrn_ResetResult (&Print);
if ((Result.ResCod = TstRes_GetParamExaCod ()) <= 0) if ((Print.PrnCod = TstPrn_GetParamExaCod ()) <= 0)
Lay_ShowErrorAndExit ("Wrong test exam."); Lay_ShowErrorAndExit ("Wrong test exam.");
/* Get number of this test from form */ /* Get number of this test from form */
NumTst = Tst_GetParamNumTst (); NumTst = Tst_GetParamNumTst ();
/***** Get test exam from database *****/ /***** Get test exam from database *****/
TstRes_GetExamDataByExaCod (&Result); TstPrn_GetExamDataByExaCod (&Print);
/****** Get test status in database for this session-course-num.test *****/ /****** Get test status in database for this session-course-num.test *****/
if (Result.Sent) if (Print.Sent)
Ale_ShowAlert (Ale_WARNING,Txt_The_test_X_has_already_been_assessed_previously, Ale_ShowAlert (Ale_WARNING,Txt_The_test_X_has_already_been_assessed_previously,
NumTst); NumTst);
else // Exam not yet sent else // Print not yet sent
{ {
/***** Get test exam questions from database *****/ /***** Get test exam questions from database *****/
TstRes_GetExamQuestionsFromDB (&Result); TstPrn_GetExamQuestionsFromDB (&Print);
/***** Get answers from form to assess a test *****/ /***** Get answers from form to assess a test *****/
Tst_GetAnswersFromForm (&Result); Tst_GetAnswersFromForm (&Print);
/***** Update test exam in database *****/ /***** Update test exam in database *****/
TstRes_ComputeScoresAndStoreExamQuestions (&Result, TstPrn_ComputeScoresAndStoreExamQuestions (&Print,
false); // Don't update question score false); // Don't update question score
TstRes_UpdateExamInDB (&Result); TstPrn_UpdateExamInDB (&Print);
/***** Show question and button to send the test *****/ /***** Show question and button to send the test *****/
/* Start alert */ /* Start alert */
Ale_ShowAlert (Ale_WARNING,"Por favor, revise sus respuestas antes de enviar el examen:"); // TODO: Need translation!!! Ale_ShowAlert (Ale_WARNING,Txt_Please_review_your_answers_before_submitting_the_exam);
/* Show the same test exam to be answered */ /* Show the same test exam to be answered */
Tst_ShowTestExamToFillIt (&Result,NumTst,Tst_CONFIRM); Tst_ShowTestExamToFillIt (&Print,NumTst,Tst_CONFIRM);
} }
} }
@ -580,43 +578,43 @@ void Tst_AssessTest (void)
extern const char *Txt_Grade; extern const char *Txt_Grade;
extern const char *Txt_The_test_X_has_already_been_assessed_previously; extern const char *Txt_The_test_X_has_already_been_assessed_previously;
unsigned NumTst; unsigned NumTst;
struct TstRes_Result Result; struct TstPrn_Print Print;
/***** Read test configuration from database *****/ /***** Read test configuration from database *****/
TstCfg_GetConfigFromDB (); TstCfg_GetConfigFromDB ();
/***** Get basic parameters of the exam *****/ /***** Get basic parameters of the exam *****/
/* Get test exam code from form */ /* Get test exam code from form */
TstRes_ResetResult (&Result); TstPrn_ResetResult (&Print);
if ((Result.ResCod = TstRes_GetParamExaCod ()) <= 0) if ((Print.PrnCod = TstPrn_GetParamExaCod ()) <= 0)
Lay_ShowErrorAndExit ("Wrong test exam."); Lay_ShowErrorAndExit ("Wrong test exam.");
/* Get number of this test from form */ /* Get number of this test from form */
NumTst = Tst_GetParamNumTst (); NumTst = Tst_GetParamNumTst ();
/***** Get test exam from database *****/ /***** Get test exam from database *****/
TstRes_GetExamDataByExaCod (&Result); TstPrn_GetExamDataByExaCod (&Print);
/****** Get test status in database for this session-course-num.test *****/ /****** Get test status in database for this session-course-num.test *****/
if (Result.Sent) if (Print.Sent)
Ale_ShowAlert (Ale_WARNING,Txt_The_test_X_has_already_been_assessed_previously, Ale_ShowAlert (Ale_WARNING,Txt_The_test_X_has_already_been_assessed_previously,
NumTst); NumTst);
else // Exam not yet sent else // Print not yet sent
{ {
/***** Get test exam questions from database *****/ /***** Get test exam questions from database *****/
TstRes_GetExamQuestionsFromDB (&Result); TstPrn_GetExamQuestionsFromDB (&Print);
/***** Get answers from form to assess a test *****/ /***** Get answers from form to assess a test *****/
Tst_GetAnswersFromForm (&Result); Tst_GetAnswersFromForm (&Print);
/***** Get if test exam will be visible by teachers *****/ /***** Get if test exam will be visible by teachers *****/
Result.Sent = true; // The exam has been finished and sent by student Print.Sent = true; // The exam has been finished and sent by student
Result.AllowTeachers = Par_GetParToBool ("AllowTchs"); Print.AllowTeachers = Par_GetParToBool ("AllowTchs");
/***** Update test exam in database *****/ /***** Update test exam in database *****/
TstRes_ComputeScoresAndStoreExamQuestions (&Result, TstPrn_ComputeScoresAndStoreExamQuestions (&Print,
Gbl.Usrs.Me.Role.Logged == Rol_STD); // Update question score? Gbl.Usrs.Me.Role.Logged == Rol_STD); // Update question score?
TstRes_UpdateExamInDB (&Result); TstPrn_UpdateExamInDB (&Print);
/***** Begin box *****/ /***** Begin box *****/
Box_BoxBegin (NULL,Txt_Test_result, Box_BoxBegin (NULL,Txt_Test_result,
@ -636,19 +634,19 @@ void Tst_AssessTest (void)
} }
/***** Write answers and solutions *****/ /***** Write answers and solutions *****/
TstRes_ShowExamAfterAssess (&Result); TstPrn_ShowExamAfterAssess (&Print);
/***** Write total score and grade *****/ /***** Write total score and grade *****/
if (TstVis_IsVisibleTotalScore (TstCfg_GetConfigVisibility ())) if (TstVis_IsVisibleTotalScore (TstCfg_GetConfigVisibility ()))
{ {
HTM_DIV_Begin ("class=\"DAT_N_BOLD CM\""); HTM_DIV_Begin ("class=\"DAT_N_BOLD CM\"");
HTM_TxtColonNBSP (Txt_Score); HTM_TxtColonNBSP (Txt_Score);
HTM_Double2Decimals (Result.Score); HTM_Double2Decimals (Print.Score);
HTM_BR (); HTM_BR ();
HTM_TxtColonNBSP (Txt_Grade); HTM_TxtColonNBSP (Txt_Grade);
TstRes_ComputeAndShowGrade (Result.NumQsts, TstPrn_ComputeAndShowGrade (Print.NumQsts,
Result.Score, Print.Score,
TstRes_SCORE_MAX); TstPrn_SCORE_MAX);
HTM_DIV_End (); HTM_DIV_End ();
} }
@ -661,22 +659,22 @@ void Tst_AssessTest (void)
/*********** Get questions and answers from form to assess a test ************/ /*********** Get questions and answers from form to assess a test ************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_GetAnswersFromForm (struct TstRes_Result *Result) static void Tst_GetAnswersFromForm (struct TstPrn_Print *Print)
{ {
unsigned NumQst; unsigned NumQst;
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x" char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
/***** Loop for every question getting user's answers *****/ /***** Loop for every question getting user's answers *****/
for (NumQst = 0; for (NumQst = 0;
NumQst < Result->NumQsts; NumQst < Print->NumQsts;
NumQst++) NumQst++)
{ {
/* Get answers selected by user for this question */ /* Get answers selected by user for this question */
snprintf (StrAns,sizeof (StrAns), snprintf (StrAns,sizeof (StrAns),
"Ans%010u", "Ans%010u",
NumQst); NumQst);
Par_GetParMultiToText (StrAns,Result->Questions[NumQst].StrAnswers, Par_GetParMultiToText (StrAns,Print->PrintedQuestions[NumQst].StrAnswers,
TstRes_MAX_BYTES_ANSWERS_ONE_QST); /* If answer type == T/F ==> " ", "T", "F"; if choice ==> "0", "2",... */ TstPrn_MAX_BYTES_ANSWERS_ONE_QST); /* If answer type == T/F ==> " ", "T", "F"; if choice ==> "0", "2",... */
} }
} }
@ -788,7 +786,7 @@ static unsigned Tst_GetNumExamsGeneratedByMe (void)
/************************ Show a test exam to be answered ********************/ /************************ Show a test exam to be answered ********************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_ShowTestExamToFillIt (struct TstRes_Result *Result, static void Tst_ShowTestExamToFillIt (struct TstPrn_Print *Print,
unsigned NumExamsGeneratedByMe, unsigned NumExamsGeneratedByMe,
Tst_RequestOrConfirm_t RequestOrConfirm) Tst_RequestOrConfirm_t RequestOrConfirm)
{ {
@ -813,11 +811,11 @@ static void Tst_ShowTestExamToFillIt (struct TstRes_Result *Result,
Gbl.Hierarchy.Deg.DegCod, Gbl.Hierarchy.Deg.DegCod,
Gbl.Hierarchy.Crs.CrsCod); Gbl.Hierarchy.Crs.CrsCod);
if (Result->NumQsts) if (Print->NumQsts)
{ {
/***** Begin form *****/ /***** Begin form *****/
Frm_StartForm (Action[RequestOrConfirm]); Frm_StartForm (Action[RequestOrConfirm]);
TstRes_PutParamExaCod (Result->ResCod); TstPrn_PutParamExaCod (Print->PrnCod);
Par_PutHiddenParamUnsigned (NULL,"NumTst",NumExamsGeneratedByMe); Par_PutHiddenParamUnsigned (NULL,"NumTst",NumExamsGeneratedByMe);
/***** Begin table *****/ /***** Begin table *****/
@ -825,21 +823,21 @@ static void Tst_ShowTestExamToFillIt (struct TstRes_Result *Result,
/***** Write one row for each question *****/ /***** Write one row for each question *****/
for (NumQst = 0; for (NumQst = 0;
NumQst < Result->NumQsts; NumQst < Print->NumQsts;
NumQst++) NumQst++)
{ {
Gbl.RowEvenOdd = NumQst % 2; Gbl.RowEvenOdd = NumQst % 2;
/* Create test question */ /* Create test question */
Tst_QstConstructor (&Question); Tst_QstConstructor (&Question);
Question.QstCod = Result->Questions[NumQst].QstCod; Question.QstCod = Print->PrintedQuestions[NumQst].QstCod;
/* Show question */ /* Show question */
if (!Tst_GetQstDataFromDB (&Question)) // Question exists if (!Tst_GetQstDataFromDB (&Question)) // Question exists
Lay_ShowErrorAndExit ("Wrong question."); Lay_ShowErrorAndExit ("Wrong question.");
/* Write question and answers */ /* Write question and answers */
Tst_WriteQstAndAnsSeeing (Result,NumQst,&Question); Tst_WriteQstAndAnsSeeing (Print,NumQst,&Question);
/* Destroy test question */ /* Destroy test question */
Tst_QstDestructor (&Question); Tst_QstDestructor (&Question);
@ -903,7 +901,7 @@ void Tst_ShowTagList (unsigned NumTags,MYSQL_RES *mysql_res)
/********** Write a row of a test, with one question and its answer **********/ /********** Write a row of a test, with one question and its answer **********/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_WriteQstAndAnsSeeing (const struct TstRes_Result *Result, static void Tst_WriteQstAndAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst, unsigned NumQst,
const struct Tst_Question *Question) const struct Tst_Question *Question)
{ {
@ -931,7 +929,7 @@ static void Tst_WriteQstAndAnsSeeing (const struct TstRes_Result *Result,
"TEST_MED_SHOW"); "TEST_MED_SHOW");
/* Answers */ /* Answers */
Tst_WriteAnswersSeeing (Result,NumQst,Question); Tst_WriteAnswersSeeing (Print,NumQst,Question);
HTM_TD_End (); HTM_TD_End ();
@ -2512,7 +2510,7 @@ static void Tst_GetQuestions (struct Tst_Test *Test,MYSQL_RES **mysql_res)
/*****************************************************************************/ /*****************************************************************************/
static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test, static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test,
struct TstRes_Result *Result) struct TstPrn_Print *Print)
{ {
MYSQL_RES *mysql_res; MYSQL_RES *mysql_res;
MYSQL_ROW row; MYSQL_ROW row;
@ -2625,14 +2623,14 @@ static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test,
Lay_ShowAlert (Lay_INFO,Query); Lay_ShowAlert (Lay_INFO,Query);
*/ */
/* Make the query */ /* Make the query */
Result->NumQsts = Print->NumQsts =
Test->NumQsts = (unsigned) DB_QuerySELECT (&mysql_res,"can not get questions", Test->NumQsts = (unsigned) DB_QuerySELECT (&mysql_res,"can not get questions",
"%s", "%s",
Query); Query);
/***** Get questions and answers from database *****/ /***** Get questions and answers from database *****/
for (NumQst = 0; for (NumQst = 0;
NumQst < Result->NumQsts; NumQst < Print->NumQsts;
NumQst++) NumQst++)
{ {
/* Get question row */ /* Get question row */
@ -2644,7 +2642,7 @@ static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test,
*/ */
/* Get question code (row[0]) */ /* Get question code (row[0]) */
if ((Result->Questions[NumQst].QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0) if ((Print->PrintedQuestions[NumQst].QstCod = Str_ConvertStrCodToLongCod (row[0])) < 0)
Lay_ShowErrorAndExit ("Wrong code of question."); Lay_ShowErrorAndExit ("Wrong code of question.");
/* Get answer type (row[1]) */ /* Get answer type (row[1]) */
@ -2660,13 +2658,13 @@ static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test,
case Tst_ANS_FLOAT: case Tst_ANS_FLOAT:
case Tst_ANS_TRUE_FALSE: case Tst_ANS_TRUE_FALSE:
case Tst_ANS_TEXT: case Tst_ANS_TEXT:
Result->Questions[NumQst].StrIndexes[0] = '\0'; Print->PrintedQuestions[NumQst].StrIndexes[0] = '\0';
break; break;
case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_UNIQUE_CHOICE:
case Tst_ANS_MULTIPLE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE:
/* If answer type is unique or multiple option, /* If answer type is unique or multiple option,
generate indexes of answers depending on shuffle */ generate indexes of answers depending on shuffle */
Tst_GenerateChoiceIndexesDependingOnShuffle (Result,NumQst,Shuffle); Tst_GenerateChoiceIndexesDependingOnShuffle (&Print->PrintedQuestions[NumQst],Shuffle);
break; break;
default: default:
break; break;
@ -2676,20 +2674,19 @@ static void Tst_GetQuestionsForNewTestFromDB (struct Tst_Test *Test,
Initially user has not answered the question ==> initially all the answers will be blank. Initially user has not answered the question ==> initially all the answers will be blank.
If the user does not confirm the submission of their exam ==> If the user does not confirm the submission of their exam ==>
==> the exam may be half filled ==> the answers displayed will be those selected by the user. */ ==> the exam may be half filled ==> the answers displayed will be those selected by the user. */
Result->Questions[NumQst].StrAnswers[0] = '\0'; Print->PrintedQuestions[NumQst].StrAnswers[0] = '\0';
} }
/***** Get if test exam will be visible by teachers *****/ /***** Get if test exam will be visible by teachers *****/
Result->AllowTeachers = Par_GetParToBool ("AllowTchs"); Print->AllowTeachers = Par_GetParToBool ("AllowTchs");
} }
/*****************************************************************************/ /*****************************************************************************/
/********* Get single or multiple choice answer when seeing a test ***********/ /********* Get single or multiple choice answer when seeing a test ***********/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_GenerateChoiceIndexesDependingOnShuffle (struct TstRes_Result *Result, void Tst_GenerateChoiceIndexesDependingOnShuffle (struct TstPrn_PrintedQuestion *PrintedQuestion,
unsigned NumQst, bool Shuffle)
bool Shuffle)
{ {
extern const char *Par_SEPARATOR_PARAM_MULTIPLE; extern const char *Par_SEPARATOR_PARAM_MULTIPLE;
struct Tst_Question Question; struct Tst_Question Question;
@ -2702,7 +2699,7 @@ static void Tst_GenerateChoiceIndexesDependingOnShuffle (struct TstRes_Result *R
/***** Create test question *****/ /***** Create test question *****/
Tst_QstConstructor (&Question); Tst_QstConstructor (&Question);
Question.QstCod = Result->Questions[NumQst].QstCod; Question.QstCod = PrintedQuestion->QstCod;
/***** Get answers of question from database *****/ /***** Get answers of question from database *****/
Tst_GetAnswersQst (&Question,&mysql_res,Shuffle); Tst_GetAnswersQst (&Question,&mysql_res,Shuffle);
@ -2739,8 +2736,8 @@ static void Tst_GenerateChoiceIndexesDependingOnShuffle (struct TstRes_Result *R
snprintf (StrInd,sizeof (StrInd),"%u",Index); snprintf (StrInd,sizeof (StrInd),"%u",Index);
else else
snprintf (StrInd,sizeof (StrInd),"%s%u",Par_SEPARATOR_PARAM_MULTIPLE,Index); snprintf (StrInd,sizeof (StrInd),"%s%u",Par_SEPARATOR_PARAM_MULTIPLE,Index);
Str_Concat (Result->Questions[NumQst].StrIndexes,StrInd, Str_Concat (PrintedQuestion->StrIndexes,StrInd,
TstRes_MAX_BYTES_INDEXES_ONE_QST); TstPrn_MAX_BYTES_INDEXES_ONE_QST);
} }
/***** Free structure that stores the query result *****/ /***** Free structure that stores the query result *****/
@ -3360,7 +3357,7 @@ void Tst_WriteAnswersListing (const struct Tst_Question *Question)
/************** Write answers of a question when seeing a test ***************/ /************** Write answers of a question when seeing a test ***************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_WriteAnswersSeeing (const struct TstRes_Result *Result, static void Tst_WriteAnswersSeeing (const struct TstPrn_Print *Print,
unsigned NumQst, unsigned NumQst,
const struct Tst_Question *Question) const struct Tst_Question *Question)
{ {
@ -3368,20 +3365,20 @@ static void Tst_WriteAnswersSeeing (const struct TstRes_Result *Result,
switch (Question->Answer.Type) switch (Question->Answer.Type)
{ {
case Tst_ANS_INT: case Tst_ANS_INT:
Tst_WriteIntAnsSeeing (Result,NumQst); Tst_WriteIntAnsSeeing (Print,NumQst);
break; break;
case Tst_ANS_FLOAT: case Tst_ANS_FLOAT:
Tst_WriteFloatAnsSeeing (Result,NumQst); Tst_WriteFloatAnsSeeing (Print,NumQst);
break; break;
case Tst_ANS_TRUE_FALSE: case Tst_ANS_TRUE_FALSE:
Tst_WriteTFAnsSeeing (Result,NumQst); Tst_WriteTFAnsSeeing (Print,NumQst);
break; break;
case Tst_ANS_UNIQUE_CHOICE: case Tst_ANS_UNIQUE_CHOICE:
case Tst_ANS_MULTIPLE_CHOICE: case Tst_ANS_MULTIPLE_CHOICE:
Tst_WriteChoiceAnsSeeing (Result,NumQst,Question); Tst_WriteChoiceAnsSeeing (Print,NumQst,Question);
break; break;
case Tst_ANS_TEXT: case Tst_ANS_TEXT:
Tst_WriteTextAnsSeeing (Result,NumQst); Tst_WriteTextAnsSeeing (Print,NumQst);
break; break;
default: default:
break; break;
@ -3417,7 +3414,7 @@ static void Tst_WriteIntAnsListing (const struct Tst_Question *Question)
/****************** Write integer answer when seeing a test ******************/ /****************** Write integer answer when seeing a test ******************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_WriteIntAnsSeeing (const struct TstRes_Result *Exam, static void Tst_WriteIntAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst) unsigned NumQst)
{ {
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x" char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
@ -3426,7 +3423,7 @@ static void Tst_WriteIntAnsSeeing (const struct TstRes_Result *Exam,
snprintf (StrAns,sizeof (StrAns), snprintf (StrAns,sizeof (StrAns),
"Ans%010u", "Ans%010u",
NumQst); NumQst);
HTM_INPUT_TEXT (StrAns,11,Exam->Questions[NumQst].StrAnswers, HTM_INPUT_TEXT (StrAns,11,Print->PrintedQuestions[NumQst].StrAnswers,
HTM_DONT_SUBMIT_ON_CHANGE, HTM_DONT_SUBMIT_ON_CHANGE,
"size=\"11\""); "size=\"11\"");
} }
@ -3450,7 +3447,7 @@ static void Tst_WriteFloatAnsEdit (const struct Tst_Question *Question)
/****************** Write float answer when seeing a test ********************/ /****************** Write float answer when seeing a test ********************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_WriteFloatAnsSeeing (const struct TstRes_Result *Exam, static void Tst_WriteFloatAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst) unsigned NumQst)
{ {
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x" char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
@ -3459,7 +3456,7 @@ static void Tst_WriteFloatAnsSeeing (const struct TstRes_Result *Exam,
snprintf (StrAns,sizeof (StrAns), snprintf (StrAns,sizeof (StrAns),
"Ans%010u", "Ans%010u",
NumQst); NumQst);
HTM_INPUT_TEXT (StrAns,Tst_MAX_BYTES_FLOAT_ANSWER,Exam->Questions[NumQst].StrAnswers, HTM_INPUT_TEXT (StrAns,Tst_MAX_BYTES_FLOAT_ANSWER,Print->PrintedQuestions[NumQst].StrAnswers,
HTM_DONT_SUBMIT_ON_CHANGE, HTM_DONT_SUBMIT_ON_CHANGE,
"size=\"11\""); "size=\"11\"");
} }
@ -3482,7 +3479,7 @@ static void Tst_WriteTFAnsListing (const struct Tst_Question *Question)
/************** Write false / true answer when seeing a test ****************/ /************** Write false / true answer when seeing a test ****************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_WriteTFAnsSeeing (const struct TstRes_Result *Exam, static void Tst_WriteTFAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst) unsigned NumQst)
{ {
extern const char *Txt_TF_QST[2]; extern const char *Txt_TF_QST[2];
@ -3493,9 +3490,9 @@ static void Tst_WriteTFAnsSeeing (const struct TstRes_Result *Exam,
==> the exam may be half filled ==> the answers displayed will be those selected by the user. */ ==> the exam may be half filled ==> the answers displayed will be those selected by the user. */
HTM_SELECT_Begin (HTM_DONT_SUBMIT_ON_CHANGE, HTM_SELECT_Begin (HTM_DONT_SUBMIT_ON_CHANGE,
"name=\"Ans%010u\"",NumQst); "name=\"Ans%010u\"",NumQst);
HTM_OPTION (HTM_Type_STRING,"" ,Exam->Questions[NumQst].StrAnswers[0] == '\0',false,"&nbsp;"); HTM_OPTION (HTM_Type_STRING,"" ,Print->PrintedQuestions[NumQst].StrAnswers[0] == '\0',false,"&nbsp;");
HTM_OPTION (HTM_Type_STRING,"T",Exam->Questions[NumQst].StrAnswers[0] == 'T' ,false,"%s",Txt_TF_QST[0]); HTM_OPTION (HTM_Type_STRING,"T",Print->PrintedQuestions[NumQst].StrAnswers[0] == 'T' ,false,"%s",Txt_TF_QST[0]);
HTM_OPTION (HTM_Type_STRING,"F",Exam->Questions[NumQst].StrAnswers[0] == 'F' ,false,"%s",Txt_TF_QST[1]); HTM_OPTION (HTM_Type_STRING,"F",Print->PrintedQuestions[NumQst].StrAnswers[0] == 'F' ,false,"%s",Txt_TF_QST[1]);
HTM_SELECT_End (); HTM_SELECT_End ();
} }
@ -3615,7 +3612,7 @@ static void Tst_WriteChoiceAnsListing (const struct Tst_Question *Question)
/******** Write single or multiple choice answer when seeing a test **********/ /******** Write single or multiple choice answer when seeing a test **********/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_WriteChoiceAnsSeeing (const struct TstRes_Result *Exam, static void Tst_WriteChoiceAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst, unsigned NumQst,
const struct Tst_Question *Question) const struct Tst_Question *Question)
{ {
@ -3625,10 +3622,10 @@ static void Tst_WriteChoiceAnsSeeing (const struct TstRes_Result *Exam,
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x" char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
/***** Get indexes for this question from string *****/ /***** Get indexes for this question from string *****/
TstRes_GetIndexesFromStr (Exam->Questions[NumQst].StrIndexes,Indexes); TstPrn_GetIndexesFromStr (Print->PrintedQuestions[NumQst].StrIndexes,Indexes);
/***** Get the user's answers for this question from string *****/ /***** Get the user's answers for this question from string *****/
TstRes_GetAnswersFromStr (Exam->Questions[NumQst].StrAnswers,UsrAnswers); TstPrn_GetAnswersFromStr (Print->PrintedQuestions[NumQst].StrAnswers,UsrAnswers);
/***** Begin table *****/ /***** Begin table *****/
HTM_TABLE_BeginPadding (2); HTM_TABLE_BeginPadding (2);
@ -3756,7 +3753,7 @@ void Tst_GetChoiceAns (struct Tst_Question *Question,MYSQL_RES *mysql_res)
/******************** Write text answer when seeing a test *******************/ /******************** Write text answer when seeing a test *******************/
/*****************************************************************************/ /*****************************************************************************/
static void Tst_WriteTextAnsSeeing (const struct TstRes_Result *Result, static void Tst_WriteTextAnsSeeing (const struct TstPrn_Print *Print,
unsigned NumQst) unsigned NumQst)
{ {
char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x" char StrAns[3 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; // "Ansxx...x"
@ -3765,7 +3762,7 @@ static void Tst_WriteTextAnsSeeing (const struct TstRes_Result *Result,
snprintf (StrAns,sizeof (StrAns), snprintf (StrAns,sizeof (StrAns),
"Ans%010u", "Ans%010u",
NumQst); NumQst);
HTM_INPUT_TEXT (StrAns,TstRes_MAX_CHARS_ANSWERS_ONE_QST,Result->Questions[NumQst].StrAnswers, HTM_INPUT_TEXT (StrAns,TstPrn_MAX_CHARS_ANSWERS_ONE_QST,Print->PrintedQuestions[NumQst].StrAnswers,
HTM_DONT_SUBMIT_ON_CHANGE, HTM_DONT_SUBMIT_ON_CHANGE,
"size=\"40\""); "size=\"40\"");
} }
@ -5052,7 +5049,7 @@ static void Tst_GetQstFromForm (struct Tst_Question *Question)
char TagStr[6 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; char TagStr[6 + Cns_MAX_DECIMAL_DIGITS_UINT + 1];
char AnsStr[6 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; char AnsStr[6 + Cns_MAX_DECIMAL_DIGITS_UINT + 1];
char FbStr[5 + Cns_MAX_DECIMAL_DIGITS_UINT + 1]; char FbStr[5 + Cns_MAX_DECIMAL_DIGITS_UINT + 1];
char StrMultiAns[TstRes_MAX_BYTES_ANSWERS_ONE_QST + 1]; char StrMultiAns[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1];
char TF[1 + 1]; // (T)rue or (F)alse char TF[1 + 1]; // (T)rue or (F)alse
const char *Ptr; const char *Ptr;
unsigned NumCorrectAns; unsigned NumCorrectAns;
@ -5204,7 +5201,7 @@ static void Tst_GetQstFromForm (struct Tst_Question *Question)
} }
else if (Question->Answer.Type == Tst_ANS_MULTIPLE_CHOICE) else if (Question->Answer.Type == Tst_ANS_MULTIPLE_CHOICE)
{ {
Par_GetParMultiToText ("AnsMulti",StrMultiAns,TstRes_MAX_BYTES_ANSWERS_ONE_QST); Par_GetParMultiToText ("AnsMulti",StrMultiAns,TstPrn_MAX_BYTES_ANSWERS_ONE_QST);
Ptr = StrMultiAns; Ptr = StrMultiAns;
while (*Ptr) while (*Ptr)
{ {

View File

@ -31,48 +31,22 @@
#include "swad_game.h" #include "swad_game.h"
#include "swad_media.h" #include "swad_media.h"
#include "swad_test_config.h" #include "swad_test_config.h"
#include "swad_test_print.h"
#include "swad_test_type.h"
/*****************************************************************************/ /*****************************************************************************/
/***************************** Public constants ******************************/ /***************************** Public constants ******************************/
/*****************************************************************************/ /*****************************************************************************/
#define Tst_MAX_TAGS_PER_QUESTION 5
#define Tst_MAX_CHARS_TAG (128 - 1) // 127
#define Tst_MAX_BYTES_TAG ((Tst_MAX_CHARS_TAG + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047
#define Tst_MAX_CHARS_ANSWER_OR_FEEDBACK (1024 - 1) // 1023 #define Tst_MAX_CHARS_ANSWER_OR_FEEDBACK (1024 - 1) // 1023
#define Tst_MAX_BYTES_ANSWER_OR_FEEDBACK ((Tst_MAX_CHARS_ANSWER_OR_FEEDBACK + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 16383 #define Tst_MAX_BYTES_ANSWER_OR_FEEDBACK ((Tst_MAX_CHARS_ANSWER_OR_FEEDBACK + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 16383
#define Tst_MAX_BYTES_ANSWER_TYPE 32 #define Tst_MAX_BYTES_ANSWER_TYPE 32
#define Tst_MAX_OPTIONS_PER_QUESTION 10
/*****************************************************************************/ /*****************************************************************************/
/******************************* Public types ********************************/ /******************************* Public types ********************************/
/*****************************************************************************/ /*****************************************************************************/
struct Tst_Tags
{
unsigned Num;
bool All;
char *List;
char Txt[Tst_MAX_TAGS_PER_QUESTION][Tst_MAX_BYTES_TAG + 1];
};
#define Tst_NUM_ANS_TYPES 6
#define Tst_MAX_BYTES_LIST_ANSWER_TYPES (Tst_NUM_ANS_TYPES * (Cns_MAX_DECIMAL_DIGITS_UINT + 1))
typedef enum
{
Tst_ANS_INT = 0,
Tst_ANS_FLOAT = 1,
Tst_ANS_TRUE_FALSE = 2,
Tst_ANS_UNIQUE_CHOICE = 3,
Tst_ANS_MULTIPLE_CHOICE = 4,
Tst_ANS_TEXT = 5,
Tst_ANS_ALL = 6, // All/any type of answer
} Tst_AnswerType_t;
struct Tst_AnswerTypes struct Tst_AnswerTypes
{ {
bool All; bool All;
@ -90,35 +64,6 @@ typedef enum
} Tst_QuestionsOrder_t; } Tst_QuestionsOrder_t;
#define Tst_DEFAULT_ORDER Tst_ORDER_STEM #define Tst_DEFAULT_ORDER Tst_ORDER_STEM
struct Tst_Question
{
long QstCod;
struct Tst_Tags Tags;
time_t EditTime;
char *Stem;
char *Feedback;
struct Media Media;
struct
{
Tst_AnswerType_t Type;
unsigned NumOptions;
bool Shuffle;
char TF;
struct
{
bool Correct;
char *Text;
char *Feedback;
struct Media Media;
} Options[Tst_MAX_OPTIONS_PER_QUESTION];
long Integer;
double FloatingPoint[2];
} Answer;
unsigned long NumHits;
unsigned long NumHitsNotBlank;
double Score;
};
struct Tst_Test struct Tst_Test
{ {
struct Tst_Tags Tags; // Selected tags struct Tst_Tags Tags; // Selected tags
@ -176,6 +121,10 @@ void Tst_RequestSelectTestsForGame (struct Gam_Games *Games);
void Tst_ListQuestionsToEdit (void); void Tst_ListQuestionsToEdit (void);
void Tst_ListQuestionsToSelectForSet (struct Exa_Exams *Exams); void Tst_ListQuestionsToSelectForSet (struct Exa_Exams *Exams);
void Tst_ListQuestionsToSelectForGame (struct Gam_Games *Games); void Tst_ListQuestionsToSelectForGame (struct Gam_Games *Games);
void Tst_GenerateChoiceIndexesDependingOnShuffle (struct TstPrn_PrintedQuestion *PrintedQuestion,
bool Shuffle);
void Tst_WriteParamEditQst (const struct Tst_Test *Test); void Tst_WriteParamEditQst (const struct Tst_Test *Test);
unsigned Tst_GetNumAnswersQst (long QstCod); unsigned Tst_GetNumAnswersQst (long QstCod);

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
// swad_test_exam.c: test exams made by users // swad_test_print.h: test exam prints made by users
#ifndef _SWAD_TST_EXA #ifndef _SWAD_TST_PRN
#define _SWAD_TST_EXA #define _SWAD_TST_PRN
/* /*
SWAD (Shared Workspace At a Distance in Spanish), SWAD (Shared Workspace At a Distance in Spanish),
is a web platform developed at the University of Granada (Spain), is a web platform developed at the University of Granada (Spain),
@ -27,85 +27,88 @@
/********************************* Headers ***********************************/ /********************************* Headers ***********************************/
/*****************************************************************************/ /*****************************************************************************/
#include "swad_test.h" #include "swad_test_config.h"
#include "swad_test_type.h"
#include "swad_user.h" #include "swad_user.h"
/*****************************************************************************/ /*****************************************************************************/
/***************************** Public constants ******************************/ /***************************** Public constants ******************************/
/*****************************************************************************/ /*****************************************************************************/
#define TstRes_MAX_BYTES_INDEXES_ONE_QST (Tst_MAX_OPTIONS_PER_QUESTION * (3 + 1)) #define TstPrn_MAX_BYTES_INDEXES_ONE_QST (Tst_MAX_OPTIONS_PER_QUESTION * (3 + 1))
#define TstRes_MAX_CHARS_ANSWERS_ONE_QST (128 - 1) // 127 #define TstPrn_MAX_CHARS_ANSWERS_ONE_QST (128 - 1) // 127
#define TstRes_MAX_BYTES_ANSWERS_ONE_QST ((TstRes_MAX_CHARS_ANSWERS_ONE_QST + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047 #define TstPrn_MAX_BYTES_ANSWERS_ONE_QST ((TstPrn_MAX_CHARS_ANSWERS_ONE_QST + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047
#define TstRes_SCORE_MAX 10 // Maximum score of a test (10 in Spain). Must be unsigned! // TODO: Make this configurable by teachers #define TstPrn_SCORE_MAX 10 // Maximum score of a test (10 in Spain). Must be unsigned! // TODO: Make this configurable by teachers
/*****************************************************************************/ /*****************************************************************************/
/******************************* Public types ********************************/ /******************************* Public types ********************************/
/*****************************************************************************/ /*****************************************************************************/
struct TstRes_Result struct TstPrn_PrintedQuestion
{ {
long ResCod; // Test result code long QstCod; // Question code
char StrIndexes[TstPrn_MAX_BYTES_INDEXES_ONE_QST + 1]; // 0 1 2 3, 3 0 2 1, etc.
char StrAnswers[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user
double Score; // Question score
bool AnswerIsNotBlank; // Answer not blank?
};
struct TstPrn_Print
{
long PrnCod; // Test print code
time_t TimeUTC[Dat_NUM_START_END_TIME]; time_t TimeUTC[Dat_NUM_START_END_TIME];
unsigned NumQsts; // Number of questions unsigned NumQsts; // Number of questions
unsigned NumQstsNotBlank; // Number of questions not blank unsigned NumQstsNotBlank; // Number of questions not blank
bool Sent; // This test result has been sent or not? bool Sent; // This test print has been sent or not?
// "Sent" means that user has clicked "Send" button after finishing // "Sent" means that user has clicked "Send" button after finishing
bool AllowTeachers; // Are teachers allowed to see this test result? bool AllowTeachers; // Are teachers allowed to see this test result?
double Score; // Total score of the test result double Score; // Total score of the test print
struct struct TstPrn_PrintedQuestion PrintedQuestions[TstCfg_MAX_QUESTIONS_PER_TEST];
{
long QstCod; // Question code
char StrIndexes[TstRes_MAX_BYTES_INDEXES_ONE_QST + 1]; // 0 1 2 3, 3 0 2 1, etc.
char StrAnswers[TstRes_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user
double Score; // Question score
bool AnswerIsNotBlank; // Answer not blank?
} Questions[TstCfg_MAX_QUESTIONS_PER_TEST];
}; };
/*****************************************************************************/ /*****************************************************************************/
/***************************** Public prototypes *****************************/ /***************************** Public prototypes *****************************/
/*****************************************************************************/ /*****************************************************************************/
void TstRes_ResetResult (struct TstRes_Result *Result); void TstPrn_ResetResult (struct TstPrn_Print *Print);
void TstRes_CreateExamInDB (struct TstRes_Result *Exam); void TstPrn_CreateExamInDB (struct TstPrn_Print *Print);
void TstRes_UpdateExamInDB (const struct TstRes_Result *Exam); void TstPrn_UpdateExamInDB (const struct TstPrn_Print *Print);
void TstRes_ShowExamAfterAssess (struct TstRes_Result *Exam); void TstPrn_ShowExamAfterAssess (struct TstPrn_Print *Print);
void TstRes_ComputeScoresAndStoreExamQuestions (struct TstRes_Result *Exam, void TstPrn_ComputeScoresAndStoreExamQuestions (struct TstPrn_Print *Print,
bool UpdateQstScore); bool UpdateQstScore);
void TstRes_ComputeChoiceAnsScore (struct TstRes_Result *Result, void TstPrn_ComputeChoiceAnsScore (struct TstPrn_Print *Print,
unsigned NumQst, unsigned NumQst,
struct Tst_Question *Question); struct Tst_Question *Question);
void TstRes_GetIndexesFromStr (const char StrIndexesOneQst[TstRes_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc. void TstPrn_GetIndexesFromStr (const char StrIndexesOneQst[TstPrn_MAX_BYTES_INDEXES_ONE_QST + 1], // 0 1 2 3, 3 0 2 1, etc.
unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]); unsigned Indexes[Tst_MAX_OPTIONS_PER_QUESTION]);
void TstRes_GetAnswersFromStr (const char StrAnswersOneQst[TstRes_MAX_BYTES_ANSWERS_ONE_QST + 1], void TstPrn_GetAnswersFromStr (const char StrAnswersOneQst[TstPrn_MAX_BYTES_ANSWERS_ONE_QST + 1],
bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION]); bool UsrAnswers[Tst_MAX_OPTIONS_PER_QUESTION]);
void TstRes_ComputeAndShowGrade (unsigned NumQsts,double Score,double MaxGrade); void TstPrn_ComputeAndShowGrade (unsigned NumQsts,double Score,double MaxGrade);
double TstRes_ComputeGrade (unsigned NumQsts,double Score,double MaxGrade); double TstPrn_ComputeGrade (unsigned NumQsts,double Score,double MaxGrade);
void TstRes_ShowGrade (double Grade,double MaxGrade); void TstPrn_ShowGrade (double Grade,double MaxGrade);
void TstRes_SelUsrsToViewUsrsExams (void); void TstPrn_SelUsrsToViewUsrsExams (void);
void TstRes_SelDatesToSeeMyExams (void); void TstPrn_SelDatesToSeeMyExams (void);
void TstRes_ShowMyExams (void); void TstPrn_ShowMyExams (void);
void TstRes_GetUsrsAndShowExams (void); void TstPrn_GetUsrsAndShowExams (void);
void TstRes_PutParamExaCod (long ExaCod); void TstPrn_PutParamExaCod (long ExaCod);
long TstRes_GetParamExaCod (void); long TstPrn_GetParamExaCod (void);
void TstRes_ShowOneExam (void); void TstPrn_ShowOneExam (void);
void TstRes_ShowExamAnswers (struct UsrData *UsrDat, void TstPrn_ShowExamAnswers (struct UsrData *UsrDat,
struct TstRes_Result *Result, struct TstPrn_Print *Print,
unsigned Visibility); unsigned Visibility);
void TstRes_GetExamDataByExaCod (struct TstRes_Result *Result); void TstPrn_GetExamDataByExaCod (struct TstPrn_Print *Print);
void TstRes_GetExamQuestionsFromDB (struct TstRes_Result *Result); void TstPrn_GetExamQuestionsFromDB (struct TstPrn_Print *Print);
void TstRes_RemoveExamsMadeByUsrInAllCrss (long UsrCod); void TstPrn_RemoveExamsMadeByUsrInAllCrss (long UsrCod);
void TstRes_RemoveExamsMadeByUsrInCrs (long UsrCod,long CrsCod); void TstPrn_RemoveExamsMadeByUsrInCrs (long UsrCod,long CrsCod);
void TstRes_RemoveCrsExams (long CrsCod); void TstPrn_RemoveCrsExams (long CrsCod);
#endif #endif

99
swad_test_type.h Normal file
View File

@ -0,0 +1,99 @@
// swad_test_type.h: definition of types for tests
#ifndef _SWAD_TST_TYP
#define _SWAD_TST_TYP
/*
SWAD (Shared Workspace At a Distance in Spanish),
is a web platform developed at the University of Granada (Spain),
and used to support university teaching.
This file is part of SWAD core.
Copyright (C) 1999-2020 Antonio Cañas Vargas
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*****************************************************************************/
/********************************* Headers ***********************************/
/*****************************************************************************/
#define Tst_MAX_TAGS_PER_QUESTION 5
#define Tst_MAX_CHARS_TAG (128 - 1) // 127
#define Tst_MAX_BYTES_TAG ((Tst_MAX_CHARS_TAG + 1) * Str_MAX_BYTES_PER_CHAR - 1) // 2047
/*****************************************************************************/
/***************************** Public constants ******************************/
/*****************************************************************************/
#define Tst_MAX_OPTIONS_PER_QUESTION 10
/*****************************************************************************/
/******************************* Public types ********************************/
/*****************************************************************************/
struct Tst_Tags
{
unsigned Num;
bool All;
char *List;
char Txt[Tst_MAX_TAGS_PER_QUESTION][Tst_MAX_BYTES_TAG + 1];
};
#define Tst_NUM_ANS_TYPES 6
#define Tst_MAX_BYTES_LIST_ANSWER_TYPES (Tst_NUM_ANS_TYPES * (Cns_MAX_DECIMAL_DIGITS_UINT + 1))
typedef enum
{
Tst_ANS_INT = 0,
Tst_ANS_FLOAT = 1,
Tst_ANS_TRUE_FALSE = 2,
Tst_ANS_UNIQUE_CHOICE = 3,
Tst_ANS_MULTIPLE_CHOICE = 4,
Tst_ANS_TEXT = 5,
Tst_ANS_ALL = 6, // All/any type of answer
} Tst_AnswerType_t;
struct Tst_Question
{
long QstCod;
struct Tst_Tags Tags;
time_t EditTime;
char *Stem;
char *Feedback;
struct Media Media;
struct
{
Tst_AnswerType_t Type;
unsigned NumOptions;
bool Shuffle;
char TF;
struct
{
bool Correct;
char *Text;
char *Feedback;
struct Media Media;
} Options[Tst_MAX_OPTIONS_PER_QUESTION];
long Integer;
double FloatingPoint[2];
} Answer;
unsigned long NumHits;
unsigned long NumHitsNotBlank;
double Score;
};
/*****************************************************************************/
/***************************** Public prototypes *****************************/
/*****************************************************************************/
#endif

View File

@ -30708,6 +30708,27 @@ const char *Txt_Please_check_your_privacy_settings =
"Por favor, verifique suas configura&ccedil;&otilde;es de privacidade."; "Por favor, verifique suas configura&ccedil;&otilde;es de privacidade.";
#endif #endif
const char *Txt_Please_review_your_answers_before_submitting_the_exam =
#if L==1 // ca
"Si us plau, revisi les seves respostes abans d'enviar l'examen.";
#elif L==2 // de
"Bitte &uuml;berpr&uuml;fen Sie Ihre Antworten, bevor Sie die Pr&uuml;fung einreichen.";
#elif L==3 // en
"Please review your answers before submitting the exam.";
#elif L==4 // es
"Por favor, revise sus respuestas antes de enviar el examen.";
#elif L==5 // fr
"S'il vous pla&icirc;t, veuillez revoir vos r&eacute;ponses avant de soumettre l'examen.";
#elif L==6 // gn
"Por favor, revise sus respuestas antes de enviar el examen."; // Okoteve traducción
#elif L==7 // it
"Si prega di rivedere le risposte prima di inviare l'esame.";
#elif L==8 // pl
"Przejrzyj swoje odpowiedzi przed przes&lstrok;aniem egzaminu.";
#elif L==9 // pt
"Por favor, revise suas respostas antes de enviar o exame.";
#endif
const char *Txt_Please_select_the_country_of_your_institution = const char *Txt_Please_select_the_country_of_your_institution =
#if L==1 // ca #if L==1 // ca
"Si us plau, seleccioneu el pa&iacute;s de la seva instituci&oacute;."; "Si us plau, seleccioneu el pa&iacute;s de la seva instituci&oacute;.";