diff --git a/Makefile b/Makefile
index 74fb67da..401ded7f 100644
--- a/Makefile
+++ b/Makefile
@@ -57,7 +57,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_statistic.o swad_string.o swad_survey.o swad_syllabus.o \
swad_system_config.o \
- swad_tab.o swad_test.o swad_test_import.o swad_test_result.o \
+ swad_tab.o swad_test.o swad_test_config.o swad_test_import.o \
+ swad_test_result.o \
swad_test_visibility.o swad_theme.o swad_timeline.o swad_timetable.o \
swad_user.o \
swad_xml.o \
diff --git a/swad_API.c b/swad_API.c
index 2b45f79a..75ff457f 100644
--- a/swad_API.c
+++ b/swad_API.c
@@ -113,6 +113,7 @@ cp -f /home/acanas/swad/swad/swad /var/www/cgi-bin/
#include "swad_notification.h"
#include "swad_password.h"
#include "swad_search.h"
+#include "swad_test_config.h"
#include "swad_test_visibility.h"
#include "swad_user.h"
#include "swad_xml.h"
@@ -4009,28 +4010,28 @@ int swad__getTestConfig (struct soap *soap,
/***** Get test configuration *****/
if ((ReturnCode = API_GetTstConfig ((long) courseCode)) != SOAP_OK)
return ReturnCode;
- getTestConfigOut->pluggable = (Gbl.Test.Config.Pluggable == Tst_PLUGGABLE_YES) ? 1 :
- 0;
- getTestConfigOut->minQuestions = (int) Gbl.Test.Config.Min;
- getTestConfigOut->defQuestions = (int) Gbl.Test.Config.Def;
- getTestConfigOut->maxQuestions = (int) Gbl.Test.Config.Max;
- getTestConfigOut->visibility = (int) Gbl.Test.Config.Visibility;
+ getTestConfigOut->pluggable = (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES) ? 1 :
+ 0;
+ getTestConfigOut->minQuestions = (int) TstCfg_GetConfigMin ();
+ getTestConfigOut->defQuestions = (int) TstCfg_GetConfigDef ();
+ getTestConfigOut->maxQuestions = (int) TstCfg_GetConfigMax ();
+ getTestConfigOut->visibility = (int) TstCfg_GetConfigVisibility ();
/* Convert from visibility to old feedback */
/* TODO: Remove these lines in 2021 */
- if (!TsV_IsVisibleTotalScore (Gbl.Test.Config.Visibility))
+ if (!TsV_IsVisibleTotalScore (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback,
"nothing",
TsR_MAX_BYTES_FEEDBACK_TYPE);
- else if (!TsV_IsVisibleEachQstScore (Gbl.Test.Config.Visibility))
+ else if (!TsV_IsVisibleEachQstScore (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback,
"totalResult",
TsR_MAX_BYTES_FEEDBACK_TYPE);
- else if (!TsV_IsVisibleCorrectAns (Gbl.Test.Config.Visibility))
+ else if (!TsV_IsVisibleCorrectAns (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback,
"eachResult",
TsR_MAX_BYTES_FEEDBACK_TYPE);
- else if (!TsV_IsVisibleFeedbackTxt (Gbl.Test.Config.Visibility))
+ else if (!TsV_IsVisibleFeedbackTxt (TstCfg_GetConfigVisibility ()))
Str_Copy (getTestConfigOut->feedback,
"eachGoodBad",
TsR_MAX_BYTES_FEEDBACK_TYPE);
@@ -4040,8 +4041,8 @@ int swad__getTestConfig (struct soap *soap,
TsR_MAX_BYTES_FEEDBACK_TYPE);
/***** Get number of tests *****/
- if (Gbl.Test.Config.Pluggable == Tst_PLUGGABLE_YES &&
- Gbl.Test.Config.Max > 0)
+ if (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES &&
+ TstCfg_GetConfigMax () > 0)
getTestConfigOut->numQuestions = API_GetNumTestQuestionsInCrs ((long) courseCode);
return SOAP_OK;
@@ -4064,13 +4065,15 @@ static int API_GetTstConfig (long CrsCod)
{
/***** Get minimun, default and maximum *****/
row = mysql_fetch_row (mysql_res);
- Tst_GetConfigFromRow (row);
+ TstCfg_GetConfigFromRow (row);
}
else // NumRows == 0
{
- Gbl.Test.Config.Pluggable = Tst_PLUGGABLE_UNKNOWN;
- Gbl.Test.Config.Min = Gbl.Test.Config.Def = Gbl.Test.Config.Max = 0;
- Gbl.Test.Config.Visibility = TsV_VISIBILITY_DEFAULT;
+ TstCfg_SetConfigPluggable (TstCfg_PLUGGABLE_UNKNOWN);
+ TstCfg_SetConfigMin (0);
+ TstCfg_SetConfigDef (0);
+ TstCfg_SetConfigMax (0);
+ TstCfg_SetConfigVisibility (TsV_VISIBILITY_DEFAULT);
}
/***** Free structure that stores the query result *****/
@@ -4170,7 +4173,7 @@ int swad__getTests (struct soap *soap,
if ((ReturnCode = API_GetTstConfig ((long) courseCode)) != SOAP_OK)
return ReturnCode;
- if (Gbl.Test.Config.Pluggable == Tst_PLUGGABLE_YES)
+ if (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_YES)
{
/***** Get tags *****/
if ((ReturnCode = API_GetTstTags (soap,
diff --git a/swad_action.c b/swad_action.c
index 32e7b6b3..8d99d2a7 100644
--- a/swad_action.c
+++ b/swad_action.c
@@ -526,7 +526,7 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] =
[ActSeeAss ] = { 15, 0,TabAss,ActSeeAss ,0x3F8,0x3C7, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Inf_ShowInfo ,"info" },
[ActSeeAsg ] = { 801, 1,TabAss,ActSeeAsg ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Asg_SeeAssignments ,"edit" },
[ActSeePrj ] = {1674, 2,TabAss,ActSeePrj ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Prj_SeeProjects ,"file-alt" },
- [ActReqTst ] = { 103, 3,TabAss,ActReqTst ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_ShowFormAskTst ,"check" },
+ [ActReqTst ] = { 103, 3,TabAss,ActReqTst ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_RequestTest ,"check" },
[ActSeeAllGam ] = {1649, 4,TabAss,ActSeeAllGam ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Gam_SeeAllGames ,"gamepad" },
[ActSeeAllSvy ] = { 966, 5,TabAss,ActSeeAllSvy ,0x3F8,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,0x3C0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Svy_SeeAllSurveys ,"poll" },
[ActSeeAllExaAnn ] = { 85, 6,TabAss,ActSeeAllExaAnn ,0x3F8,0x3C7, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_ListExamAnnouncementsSee ,"bullhorn" },
@@ -629,7 +629,7 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] =
[ActSeeTst ] = { 29,-1,TabUnk,ActReqTst ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_ShowNewTest ,NULL},
[ActAssTst ] = { 98,-1,TabUnk,ActReqTst ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_AssessTest ,NULL},
- [ActEdiTstQst ] = { 104,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,Dat_SetIniEndDates ,Tst_ShowFormAskEditTsts ,NULL},
+ [ActEdiTstQst ] = { 104,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,Dat_SetIniEndDates ,Tst_RequestEditTests ,NULL},
[ActEdiOneTstQst ] = { 105,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_ShowFormEditOneQst ,NULL},
[ActReqImpTstQst ] = {1007,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TsI_ShowFormImportQstsFromXML ,NULL},
[ActImpTstQst ] = {1008,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_DATA,Act_BRW_1ST_TAB,NULL ,TsI_ImportQstsFromXML ,NULL},
@@ -645,7 +645,7 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] =
[ActEnableTag ] = { 453,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_EnableTag ,NULL},
[ActDisableTag ] = { 452,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_DisableTag ,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 ,Tst_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 ,TsR_SelDatesToSeeMyTstResults ,NULL},
[ActSeeMyTstRes ] = {1084,-1,TabUnk,ActReqTst ,0x208,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TsR_ShowMyTstResults ,NULL},
diff --git a/swad_changelog.h b/swad_changelog.h
index ce90ffa3..9ffd3725 100644
--- a/swad_changelog.h
+++ b/swad_changelog.h
@@ -497,7 +497,7 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD:
ps2pdf source.ps destination.pdf
*/
-#define Log_PLATFORM_VERSION "SWAD 19.149.2 (2020-03-19)"
+#define Log_PLATFORM_VERSION "SWAD 19.151 (2020-03-21)"
#define CSS_FILE "swad19.146.css"
#define JS_FILE "swad19.91.1.js"
/*
@@ -524,6 +524,8 @@ Param
// TODO: Oresti Baños: cambiar ojos por candados en descriptores para prohibir/permitir y dejar los ojos para poder elegir descriptores
// TODO: Si el alumno ha marcado "Permitir que los profesores...", entonces pedir confirmación al pulsar el botón azul, para evitar que se envíe por error antes de tiempo
+ Version 19.151: Mar 21, 2020 Code refactoring in tests.
+ New module swad_test_config for test configuration. (283349 lines)
Version 19.150: Mar 19, 2020 Code refactoring in tests. (283031 lines)
Version 19.149.2: Mar 19, 2020 Code refactoring in tests. (283062 lines)
Version 19.149.1: Mar 18, 2020 Code refactoring in tests. (283094 lines)
diff --git a/swad_game.c b/swad_game.c
index 48f51a04..c09f8487 100644
--- a/swad_game.c
+++ b/swad_game.c
@@ -1608,7 +1608,7 @@ void Gam_RequestNewQuestion (void)
{
/***** Show form to create a new question in this game *****/
Gam_SetCurrentGamCod (Game.GamCod); // Used to pass parameter
- Tst_ShowFormAskSelectTstsForGame ();
+ Tst_RequestSelectTestsForGame ();
}
else
Lay_NoPermissionExit ();
diff --git a/swad_global.c b/swad_global.c
index a5fbcf25..b891dfd0 100644
--- a/swad_global.c
+++ b/swad_global.c
@@ -48,6 +48,7 @@
#include "swad_project.h"
#include "swad_role.h"
#include "swad_setting.h"
+#include "swad_test_config.h"
#include "swad_test_visibility.h"
#include "swad_theme.h"
@@ -357,17 +358,13 @@ void Gbl_InitializeGlobals (void)
Gbl.Usrs.Connected.TimeToRefreshInMs = Con_MAX_TIME_TO_REFRESH_CONNECTED_IN_MS;
/* Tests */
- Gbl.Test.Config.Pluggable = Tst_PLUGGABLE_UNKNOWN;
- Gbl.Test.Config.Visibility = TsV_VISIBILITY_DEFAULT;
- Gbl.Test.NumQsts = Tst_CONFIG_DEFAULT_DEF_QUESTIONS;
+ // Tst_SetConfigPluggable (TstCfg_PLUGGABLE_UNKNOWN);
+ // Tst_SetConfigVisibility (TsV_VISIBILITY_DEFAULT);
+ Gbl.Test.NumQsts = TstCfg_DEFAULT_DEF_QUESTIONS;
Gbl.Test.AllowTeachers = true; // Test result will be visible by teachers?
Gbl.Test.AllAnsTypes = false;
Gbl.Test.ListAnsTypes[0] = '\0';
- Gbl.Test.Tags.Num = 0;
- Gbl.Test.Tags.All = false;
- Gbl.Test.Tags.List = NULL;
-
/* Games for remote control */
Gbl.Games.ListQuestions = NULL;
@@ -491,7 +488,6 @@ void Gbl_Cleanup (void)
Usr_FreeListOtherRecipients ();
Usr_FreeListsSelectedEncryptedUsrsCods (&Gbl.Usrs.Selected);
Syl_FreeListItemsSyllabus ();
- Tst_FreeTagsList ();
Exa_FreeMemExamAnnouncement ();
Exa_FreeListExamAnnouncements ();
if (Gbl.F.Tmp)
diff --git a/swad_global.h b/swad_global.h
index e7a281a0..fc8d9034 100644
--- a/swad_global.h
+++ b/swad_global.h
@@ -651,18 +651,10 @@ struct Globals
} TimeTable;
struct
{
- struct Tst_Config Config;
- struct
- {
- unsigned Num;
- bool All;
- char *List;
- char Txt[Tst_MAX_TAGS_PER_QUESTION][Tst_MAX_BYTES_TAG + 1];
- } Tags;
unsigned NumQsts;
- long QstCodes[Tst_MAX_QUESTIONS_PER_TEST]; // Codes of the sent/received questions in a test
- char StrIndexesOneQst[Tst_MAX_QUESTIONS_PER_TEST][Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; // 0 1 2 3, 3 0 2 1, etc.
- char StrAnswersOneQst[Tst_MAX_QUESTIONS_PER_TEST][Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user
+ long QstCodes[TstCfg_MAX_QUESTIONS_PER_TEST]; // Codes of the sent/received questions in a test
+ char StrIndexesOneQst[TstCfg_MAX_QUESTIONS_PER_TEST][Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; // 0 1 2 3, 3 0 2 1, etc.
+ char StrAnswersOneQst[TstCfg_MAX_QUESTIONS_PER_TEST][Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user
bool AllowTeachers; // Can teachers of this course see the test result?
bool AllAnsTypes;
char ListAnsTypes[Tst_MAX_BYTES_LIST_ANSWER_TYPES + 1];
diff --git a/swad_match_result.c b/swad_match_result.c
index dd38e19e..06a8bc08 100644
--- a/swad_match_result.c
+++ b/swad_match_result.c
@@ -151,7 +151,7 @@ static void McR_ListMyMchResultsInCrs (void)
McR_ShowHeaderMchResults (Usr_ME);
/***** List my matches results in the current course *****/
- Tst_GetConfigTstFromDB (); // Get feedback type
+ TstCfg_GetConfigFromDB (); // Get feedback type
McR_BuildGamesSelectedCommas (&GamesSelectedCommas);
McR_ShowMchResults (Usr_ME,-1L,-1L,GamesSelectedCommas);
free (GamesSelectedCommas);
@@ -193,7 +193,7 @@ static void McR_ListMyMchResultsInGam (long GamCod)
McR_ShowHeaderMchResults (Usr_ME);
/***** List my matches results in game *****/
- Tst_GetConfigTstFromDB (); // Get feedback type
+ TstCfg_GetConfigFromDB (); // Get feedback type
McR_ShowMchResults (Usr_ME,-1L,GamCod,NULL);
}
@@ -237,7 +237,7 @@ static void McR_ListMyMchResultsInMch (long MchCod)
McR_ShowHeaderMchResults (Usr_ME);
/***** List my matches results in game *****/
- Tst_GetConfigTstFromDB (); // Get feedback type
+ TstCfg_GetConfigFromDB (); // Get feedback type
McR_ShowMchResults (Usr_ME,MchCod,-1L,NULL);
}
diff --git a/swad_test.c b/swad_test.c
index d6d49b0d..43bd81d5 100644
--- a/swad_test.c
+++ b/swad_test.c
@@ -50,6 +50,7 @@
#include "swad_parameter.h"
#include "swad_theme.h"
#include "swad_test.h"
+#include "swad_test_config.h"
#include "swad_test_import.h"
#include "swad_test_visibility.h"
#include "swad_user.h"
@@ -77,13 +78,6 @@ const char *Tst_StrAnswerTypesXML[Tst_NUM_ANS_TYPES] =
#define Tst_MAX_BYTES_TAGS_LIST (16 * 1024)
#define Tst_MAX_BYTES_FLOAT_ANSWER 30 // Maximum length of the strings that store an floating point answer
-static const char *Tst_PluggableDB[Tst_NUM_OPTIONS_PLUGGABLE] =
- {
- [Tst_PLUGGABLE_UNKNOWN] = "unknown",
- [Tst_PLUGGABLE_NO ] = "N",
- [Tst_PLUGGABLE_YES ] = "Y",
- };
-
static const char *Tst_StrAnswerTypesDB[Tst_NUM_ANS_TYPES] =
{
[Tst_ANS_INT ] = "int",
@@ -125,11 +119,16 @@ extern struct Globals Gbl;
/*****************************************************************************/
static long Tst_ParamGblQstCod = -1L; // Used to pass parameter to function
+struct Tst_Test Tst_Test;
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
+static void Tst_ResetTags (struct Tst_Tags *Tags);
+
+static void Tst_ShowFormRequestTest (const struct Tst_Tags *Tags);
+
static void Tst_GetQuestionsAndAnswersFromForm (void);
static bool Tst_CheckIfNextTstAllowed (void);
static void Tst_SetTstStatus (unsigned NumTst,Tst_Status_t TstStatus);
@@ -143,6 +142,9 @@ static void Tst_PutFormToEditQstMedia (const struct Media *Media,int NumMediaInF
static void Tst_UpdateScoreQst (long QstCod,double ScoreThisQst,bool AnswerIsNotBlank);
static void Tst_UpdateMyNumAccessTst (unsigned NumAccessesTst);
static void Tst_UpdateLastAccTst (void);
+
+static void Tst_ShowFormRequestEditTests (const struct Tst_Tags *Tags);
+static void Tst_ShowFormRequestSelectTestsForGame (const struct Tst_Tags *Tags);
static bool Tst_CheckIfICanEditTests (void);
static void Tst_PutIconsTests (void);
static void Tst_PutButtonToAddQuestion (void);
@@ -151,24 +153,30 @@ static long Tst_GetParamTagCode (void);
static bool Tst_CheckIfCurrentCrsHasTestTags (void);
static unsigned long Tst_GetAllTagsFromCurrentCrs (MYSQL_RES **mysql_res);
static unsigned long Tst_GetEnabledTagsFromThisCrs (MYSQL_RES **mysql_res);
-static void Tst_ShowFormSelTags (unsigned long NumRows,MYSQL_RES *mysql_res,
+static void Tst_ShowFormSelTags (const struct Tst_Tags *Tags,
+ unsigned long NumRows,MYSQL_RES *mysql_res,
bool ShowOnlyEnabledTags);
static void Tst_ShowFormEditTags (void);
static void Tst_PutIconEnable (long TagCod,const char *TagTxt);
static void Tst_PutIconDisable (long TagCod,const char *TagTxt);
static void Tst_ShowFormConfigTst (void);
+
static void Tst_PutInputFieldNumQst (const char *Field,const char *Label,
unsigned Value);
-static Tst_Pluggable_t Tst_GetPluggableFromForm (void);
-static void Tst_CheckAndCorrectNumbersQst (void);
+
static void Tst_ShowFormAnswerTypes (void);
-static unsigned long Tst_GetQuestions (MYSQL_RES **mysql_res);
-static unsigned long Tst_GetQuestionsForTest (MYSQL_RES **mysql_res);
-static void Tst_ListOneQstToEdit (long QstCod);
-static void Tst_ListOneOrMoreQuestionsForEdition (unsigned long NumRows,
+static unsigned long Tst_GetQuestions (const struct Tst_Tags *Tags,
+ MYSQL_RES **mysql_res);
+static unsigned long Tst_GetQuestionsForTest (const struct Tst_Tags *Tags,
+ MYSQL_RES **mysql_res);
+static void Tst_ListOneQstToEdit (long QstCod,const struct Tst_Tags *Tags);
+static void Tst_ListOneOrMoreQuestionsForEdition (const struct Tst_Tags *Tags,
+ unsigned long NumRows,
MYSQL_RES *mysql_res);
-static void Tst_WriteHeadingRowQuestionsForEdition (unsigned long NumRows);
-static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
+static void Tst_WriteHeadingRowQuestionsForEdition (const struct Tst_Tags *Tags,
+ unsigned long NumRows);
+static void Tst_WriteQuestionRowForEdition (const struct Tst_Tags *Tags,
+ unsigned long NumRows,
unsigned long NumRow,
long QstCod);
static void Tst_ListOneOrMoreQuestionsForSelection (unsigned long NumRows,
@@ -235,13 +243,18 @@ static void Tst_WriteHeadUserCorrect (struct UsrData *UsrDat);
static void Tst_WriteScoreStart (unsigned ColSpan);
static void Tst_WriteScoreEnd (void);
static void Tst_WriteParamQstCod (unsigned NumQst,long QstCod);
-static bool Tst_GetParamsTst (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions);
+static bool Tst_GetParamsTst (struct Tst_Tags *Tags,
+ Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions);
static unsigned Tst_GetAndCheckParamNumTst (void);
static void Tst_GetParamNumQst (void);
-static int Tst_CountNumTagsInList (void);
+static unsigned Tst_CountNumTagsInList (const struct Tst_Tags *Tags);
static int Tst_CountNumAnswerTypesInList (void);
+
+static void Tst_FreeTagsList (struct Tst_Tags *Tags);
+
static void Tst_PutFormEditOneQst (long QstCod,
const struct Tst_Question *Question,
+ const struct Tst_Tags *Tags,
char Stem[Cns_MAX_BYTES_TEXT + 1],
char Feedback[Cns_MAX_BYTES_TEXT + 1]);
static void Tst_PutFloatInputField (const char *Label,const char *Field,
@@ -258,6 +271,7 @@ static void Tst_FreeMediaOfQuestion (struct Tst_Question *Question);
static void Tst_GetQstDataFromDB (long QstCod,
struct Tst_Question *Question,
+ struct Tst_Tags *Tags,
char Stem[Cns_MAX_BYTES_TEXT + 1],
char Feedback[Cns_MAX_BYTES_TEXT + 1]);
static long Tst_GetMedCodFromDB (long CrsCod,long QstCod,int NumOpt);
@@ -266,6 +280,7 @@ static void Tst_GetMediaFromDB (long CrsCod,long QstCod,int NumOpt,
static Tst_AnswerType_t Tst_ConvertFromUnsignedStrToAnsTyp (const char *UnsignedStr);
static long Tst_GetQstFromForm (struct Tst_Question *Question,
+ struct Tst_Tags *Tags,
char *Stem,char *Feedback);
static void Tst_MoveMediaToDefinitiveDirectories (long QstCod,
struct Tst_Question *Question);
@@ -284,7 +299,7 @@ static long Tst_GetQstCod (void);
static long Tst_InsertOrUpdateQstIntoDB (long QstCod,
const struct Tst_Question *Question);
-static void Tst_InsertTagsIntoDB (long QstCod);
+static void Tst_InsertTagsIntoDB (long QstCod,const struct Tst_Tags *Tags);
static void Tst_InsertAnswersIntoDB (long QstCod,struct Tst_Question *Question);
static void Tst_RemAnsFromQst (long QstCod);
@@ -299,11 +314,37 @@ static unsigned Tst_GetNumTstQuestions (Hie_Level_t Scope,Tst_AnswerType_t AnsTy
static unsigned Tst_GetNumCoursesWithTstQuestions (Hie_Level_t Scope,Tst_AnswerType_t AnsType);
static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Tst_AnswerType_t AnsType);
+/*****************************************************************************/
+/********************* Request a self-assessment test ************************/
+/*****************************************************************************/
+
+void Tst_RequestTest (void)
+ {
+ struct Tst_Tags Tags;
+
+ /***** Reset tags *****/
+ Tst_ResetTags (&Tags);
+
+ /***** Show form to generate a self-assessment test *****/
+ Tst_ShowFormRequestTest (&Tags);
+ }
+
+/*****************************************************************************/
+/********************************* Reset tags ********************************/
+/*****************************************************************************/
+
+static void Tst_ResetTags (struct Tst_Tags *Tags)
+ {
+ Tags->Num = 0;
+ Tags->All = false;
+ Tags->List = NULL;
+ }
+
/*****************************************************************************/
/*************** Show form to generate a self-assessment test ****************/
/*****************************************************************************/
-void Tst_ShowFormAskTst (void)
+static void Tst_ShowFormRequestTest (const struct Tst_Tags *Tags)
{
extern const char *Hlp_ASSESSMENT_Tests;
extern const char *Txt_Take_a_test;
@@ -314,9 +355,10 @@ void Tst_ShowFormAskTst (void)
unsigned long NumRows;
/***** Read test configuration from database *****/
- Tst_GetConfigTstFromDB ();
+ TstCfg_GetConfigFromDB ();
/***** Begin box *****/
+ Tst_SetParamGblTags (Tags);
Box_BoxBegin (NULL,Txt_Take_a_test,Tst_PutIconsTests,
Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE);
@@ -331,7 +373,7 @@ void Tst_ShowFormAskTst (void)
HTM_TABLE_BeginPadding (2);
/***** Selection of tags *****/
- Tst_ShowFormSelTags (NumRows,mysql_res,true);
+ Tst_ShowFormSelTags (Tags,NumRows,mysql_res,true);
/***** Selection of types of answers *****/
Tst_ShowFormAnswerTypes ();
@@ -345,11 +387,11 @@ void Tst_ShowFormAskTst (void)
/* Data */
HTM_TD_Begin ("class=\"LT\"");
HTM_INPUT_LONG ("NumQst",
- (long) Gbl.Test.Config.Min,
- (long) Gbl.Test.Config.Max,
- (long) Gbl.Test.Config.Def,
- Gbl.Test.Config.Min == Gbl.Test.Config.Max,
- "id=\"NumQst\"");
+ (long) TstCfg_GetConfigMin (),
+ (long) TstCfg_GetConfigMax (),
+ (long) TstCfg_GetConfigDef (),
+ TstCfg_GetConfigMin () == TstCfg_GetConfigMax (),
+ "id=\"NumQst\"");
HTM_TD_End ();
HTM_TR_End ();
@@ -390,23 +432,24 @@ void Tst_ShowNewTest (void)
extern const char *Txt_Test;
extern const char *Txt_Allow_teachers_to_consult_this_test;
extern const char *Txt_Done_assess_test;
+ struct Tst_Tags Tags;
MYSQL_RES *mysql_res;
unsigned long NumRows;
unsigned NumAccessesTst;
/***** Read test configuration from database *****/
- Tst_GetConfigTstFromDB ();
+ TstCfg_GetConfigFromDB ();
if (Tst_CheckIfNextTstAllowed ())
{
/***** Check that all parameters used to generate a test are valid *****/
- if (Tst_GetParamsTst (Tst_SHOW_TEST_TO_ANSWER)) // Get parameters from form
+ if (Tst_GetParamsTst (&Tags,Tst_SHOW_TEST_TO_ANSWER)) // Get parameters from form
{
/***** Get questions *****/
- if ((NumRows = Tst_GetQuestionsForTest (&mysql_res)) == 0) // Query database
+ if ((NumRows = Tst_GetQuestionsForTest (&Tags,&mysql_res)) == 0) // Query database
{
Ale_ShowAlert (Ale_INFO,Txt_No_questions_found_matching_your_search_criteria);
- Tst_ShowFormAskTst (); // Show the form again
+ Tst_ShowFormRequestTest (&Tags); // Show the form again
}
else
{
@@ -464,10 +507,10 @@ void Tst_ShowNewTest (void)
DB_FreeMySQLResult (&mysql_res);
}
else
- Tst_ShowFormAskTst (); // Show the form again
+ Tst_ShowFormRequestTest (&Tags); // Show the form again
/***** Free memory used for by the list of tags *****/
- Tst_FreeTagsList ();
+ Tst_FreeTagsList (&Tags);
}
}
@@ -490,7 +533,7 @@ void Tst_AssessTest (void)
double TotalScore;
/***** Read test configuration from database *****/
- Tst_GetConfigTstFromDB ();
+ TstCfg_GetConfigFromDB ();
/***** Get number of this test from form *****/
NumTst = Tst_GetAndCheckParamNumTst ();
@@ -534,7 +577,7 @@ void Tst_AssessTest (void)
HTM_TABLE_End ();
/***** Write total score and grade *****/
- if (TsV_IsVisibleTotalScore (Gbl.Test.Config.Visibility))
+ if (TsV_IsVisibleTotalScore (TstCfg_GetConfigVisibility ()))
{
HTM_DIV_Begin ("class=\"DAT_N_BOLD CM\"");
HTM_TxtColonNBSP (Txt_Score);
@@ -673,8 +716,8 @@ static bool Tst_CheckIfNextTstAllowed (void)
"UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)" // row[1]
" FROM crs_usr"
" WHERE CrsCod=%ld AND UsrCod=%ld",
- Gbl.Test.Config.MinTimeNxtTstPerQst,
- Gbl.Test.Config.MinTimeNxtTstPerQst,
+ TstCfg_GetConfigMinTimeNxtTstPerQst (),
+ TstCfg_GetConfigMinTimeNxtTstPerQst (),
Gbl.Hierarchy.Crs.CrsCod,Gbl.Usrs.Me.UsrDat.UsrCod) == 1)
{
/* Get seconds from now to next access to test */
@@ -952,7 +995,7 @@ static void Tst_ShowTestResultAfterAssess (long TstCod,unsigned *NumQstsNotBlank
NumQst,
Gbl.Test.QstCodes[NumQst],
row,
- Gbl.Test.Config.Visibility,
+ TstCfg_GetConfigVisibility (),
&ScoreThisQst,&AnswerIsNotBlank);
/***** Store test result question in database *****/
@@ -1260,11 +1303,26 @@ static void Tst_UpdateLastAccTst (void)
Gbl.Usrs.Me.UsrDat.UsrCod);
}
+/*****************************************************************************/
+/*********************** Request the edition of tests ************************/
+/*****************************************************************************/
+
+void Tst_RequestEditTests (void)
+ {
+ struct Tst_Tags Tags;
+
+ /***** Reset tags *****/
+ Tst_ResetTags (&Tags);
+
+ /***** Show form to generate a self-assessment test *****/
+ Tst_ShowFormRequestEditTests (&Tags);
+ }
+
/*****************************************************************************/
/******* Select tags and dates for edition of the self-assessment test *******/
/*****************************************************************************/
-void Tst_ShowFormAskEditTsts (void)
+static void Tst_ShowFormRequestEditTests (const struct Tst_Tags *Tags)
{
extern const char *Hlp_ASSESSMENT_Tests_editing_questions;
extern const char *Txt_No_test_questions;
@@ -1284,6 +1342,7 @@ void Tst_ShowFormAskEditTsts (void)
Mnu_ContextMenuEnd ();
/***** Begin box *****/
+ Tst_SetParamGblTags (Tags);
Box_BoxBegin (NULL,Txt_List_edit_questions,Tst_PutIconsTests,
Hlp_ASSESSMENT_Tests_editing_questions,Box_NOT_CLOSABLE);
@@ -1296,7 +1355,7 @@ void Tst_ShowFormAskEditTsts (void)
HTM_TABLE_BeginPadding (2);
/***** Selection of tags *****/
- Tst_ShowFormSelTags (NumRows,mysql_res,false);
+ Tst_ShowFormSelTags (Tags,NumRows,mysql_res,false);
/***** Selection of types of answers *****/
Tst_ShowFormAnswerTypes ();
@@ -1327,10 +1386,25 @@ void Tst_ShowFormAskEditTsts (void)
}
/*****************************************************************************/
-/************** Show form select test questions for a game *******************/
+/******************* Select test questions for a game ************************/
/*****************************************************************************/
-void Tst_ShowFormAskSelectTstsForGame (void)
+void Tst_RequestSelectTestsForGame (void)
+ {
+ struct Tst_Tags Tags;
+
+ /***** Reset tags *****/
+ Tst_ResetTags (&Tags);
+
+ /***** Show form to select test for game *****/
+ Tst_ShowFormRequestSelectTestsForGame (&Tags);
+ }
+
+/*****************************************************************************/
+/************** Show form to select test questions for a game ****************/
+/*****************************************************************************/
+
+static void Tst_ShowFormRequestSelectTestsForGame (const struct Tst_Tags *Tags)
{
extern const char *Hlp_ASSESSMENT_Games_questions;
extern const char *Txt_No_test_questions;
@@ -1357,7 +1431,7 @@ void Tst_ShowFormAskSelectTstsForGame (void)
HTM_TABLE_BeginPadding (2);
/***** Selection of tags *****/
- Tst_ShowFormSelTags (NumRows,mysql_res,false);
+ Tst_ShowFormSelTags (Tags,NumRows,mysql_res,false);
/***** Starting and ending dates in the search *****/
Dat_PutFormStartEndClientLocalDateTimesWithYesterdayToday (SetHMS);
@@ -1646,6 +1720,55 @@ void Tst_RenameTag (void)
Tst_ShowFormConfig ();
}
+/*****************************************************************************/
+/*************** Get configuration of test for current course ****************/
+/*****************************************************************************/
+// Returns true if course has test tags and pluggable is unknown
+// Return false if course has no test tags or pluggable is known
+
+bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void)
+ {
+ extern const char *TstCfg_PluggableDB[TstCfg_NUM_OPTIONS_PLUGGABLE];
+ MYSQL_RES *mysql_res;
+ MYSQL_ROW row;
+ unsigned long NumRows;
+ TstCfg_Pluggable_t Pluggable;
+
+ /***** Get pluggability of tests for current course from database *****/
+ NumRows = DB_QuerySELECT (&mysql_res,"can not get configuration of test",
+ "SELECT Pluggable" // row[0]
+ " FROM tst_config"
+ " WHERE CrsCod=%ld",
+ Gbl.Hierarchy.Crs.CrsCod);
+
+ if (NumRows == 0)
+ TstCfg_SetConfigPluggable (TstCfg_PLUGGABLE_UNKNOWN);
+ else // NumRows == 1
+ {
+ /***** Get whether test are visible via plugins or not *****/
+ row = mysql_fetch_row (mysql_res);
+
+ TstCfg_SetConfigPluggable (TstCfg_PLUGGABLE_UNKNOWN);
+ for (Pluggable = TstCfg_PLUGGABLE_NO;
+ Pluggable <= TstCfg_PLUGGABLE_YES;
+ Pluggable++)
+ if (!strcmp (row[0],TstCfg_PluggableDB[Pluggable]))
+ {
+ TstCfg_SetConfigPluggable (Pluggable);
+ break;
+ }
+ }
+
+ /***** Free structure that stores the query result *****/
+ DB_FreeMySQLResult (&mysql_res);
+
+ /***** Get if current course has tests from database *****/
+ if (TstCfg_GetConfigPluggable () == TstCfg_PLUGGABLE_UNKNOWN)
+ return Tst_CheckIfCurrentCrsHasTestTags (); // Return true if course has tests
+
+ return false; // Pluggable is not unknown
+ }
+
/*****************************************************************************/
/******************* Check if current course has test tags *******************/
/*****************************************************************************/
@@ -1699,7 +1822,8 @@ static unsigned long Tst_GetEnabledTagsFromThisCrs (MYSQL_RES **mysql_res)
/********************* Show a form to select test tags ***********************/
/*****************************************************************************/
-static void Tst_ShowFormSelTags (unsigned long NumRows,MYSQL_RES *mysql_res,
+static void Tst_ShowFormSelTags (const struct Tst_Tags *Tags,
+ unsigned long NumRows,MYSQL_RES *mysql_res,
bool ShowOnlyEnabledTags)
{
extern const char *The_ClassFormInBox[The_NUM_THEMES];
@@ -1737,8 +1861,8 @@ static void Tst_ShowFormSelTags (unsigned long NumRows,MYSQL_RES *mysql_res,
HTM_LABEL_Begin ("class=\"%s\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
HTM_INPUT_CHECKBOX ("AllTags",HTM_DONT_SUBMIT_ON_CHANGE,
"value=\"Y\"%s onclick=\"togglecheckChildren(this,'ChkTag');\"",
- Gbl.Test.Tags.All ? " checked=\"checked\"" :
- "");
+ Tags->All ? " checked=\"checked\"" :
+ "");
HTM_TxtF (" %s",Txt_All_tags);
HTM_LABEL_End ();
HTM_TD_End ();
@@ -1765,9 +1889,9 @@ static void Tst_ShowFormSelTags (unsigned long NumRows,MYSQL_RES *mysql_res,
}
Checked = false;
- if (Gbl.Test.Tags.List)
+ if (Tags->List)
{
- Ptr = Gbl.Test.Tags.List;
+ Ptr = Tags->List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tst_MAX_BYTES_TAG);
@@ -1912,7 +2036,7 @@ static void Tst_ShowFormConfigTst (void)
extern const char *The_ClassFormInBox[The_NUM_THEMES];
extern const char *Txt_Configure_tests;
extern const char *Txt_Plugins;
- extern const char *Txt_TST_PLUGGABLE[Tst_NUM_OPTIONS_PLUGGABLE];
+ extern const char *Txt_TST_PLUGGABLE[TstCfg_NUM_OPTIONS_PLUGGABLE];
extern const char *Txt_No_of_questions;
extern const char *Txt_minimum;
extern const char *Txt_default;
@@ -1920,13 +2044,14 @@ static void Tst_ShowFormConfigTst (void)
extern const char *Txt_Minimum_time_seconds_per_question_between_two_tests;
extern const char *Txt_Result_visibility;
extern const char *Txt_Save_changes;
- Tst_Pluggable_t Pluggable;
+ TstCfg_Pluggable_t Pluggable;
char StrMinTimeNxtTstPerQst[Cns_MAX_DECIMAL_DIGITS_ULONG + 1];
/***** Read test configuration from database *****/
- Tst_GetConfigTstFromDB ();
+ TstCfg_GetConfigFromDB ();
/***** Begin box *****/
+ Tst_ResetGblTags ();
Box_BoxBegin (NULL,Txt_Configure_tests,Tst_PutIconsTests,
Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE);
@@ -1942,15 +2067,16 @@ static void Tst_ShowFormConfigTst (void)
HTM_TD_End ();
HTM_TD_Begin ("class=\"LB\"");
- for (Pluggable = Tst_PLUGGABLE_NO;
- Pluggable <= Tst_PLUGGABLE_YES;
+ for (Pluggable = TstCfg_PLUGGABLE_NO;
+ Pluggable <= TstCfg_PLUGGABLE_YES;
Pluggable++)
{
HTM_LABEL_Begin ("class=\"DAT\"");
HTM_INPUT_RADIO ("Pluggable",false,
"value=\"%u\"%s",
(unsigned) Pluggable,
- Pluggable == Gbl.Test.Config.Pluggable ? " checked=\"checked\"" : "");
+ Pluggable == TstCfg_GetConfigPluggable () ? " checked=\"checked\"" :
+ "");
HTM_Txt (Txt_TST_PLUGGABLE[Pluggable]);
HTM_LABEL_End ();
HTM_BR ();
@@ -1969,11 +2095,11 @@ static void Tst_ShowFormConfigTst (void)
HTM_TD_Begin ("class=\"LB\"");
HTM_TABLE_BeginPadding (2);
Tst_PutInputFieldNumQst ("NumQstMin",Txt_minimum,
- Gbl.Test.Config.Min); // Minimum number of questions
+ TstCfg_GetConfigMin ()); // Minimum number of questions
Tst_PutInputFieldNumQst ("NumQstDef",Txt_default,
- Gbl.Test.Config.Def); // Default number of questions
+ TstCfg_GetConfigDef ()); // Default number of questions
Tst_PutInputFieldNumQst ("NumQstMax",Txt_maximum,
- Gbl.Test.Config.Max); // Maximum number of questions
+ TstCfg_GetConfigMax ()); // Maximum number of questions
HTM_TABLE_End ();
HTM_TD_End ();
@@ -1990,7 +2116,7 @@ static void Tst_ShowFormConfigTst (void)
HTM_TD_Begin ("class=\"LB\"");
snprintf (StrMinTimeNxtTstPerQst,sizeof (StrMinTimeNxtTstPerQst),
"%lu",
- Gbl.Test.Config.MinTimeNxtTstPerQst);
+ TstCfg_GetConfigMinTimeNxtTstPerQst ());
HTM_INPUT_TEXT ("MinTimeNxtTstPerQst",Cns_MAX_DECIMAL_DIGITS_ULONG,StrMinTimeNxtTstPerQst,false,
"id=\"MinTimeNxtTstPerQst\" size=\"7\" required=\"required\"");
HTM_TD_End ();
@@ -2005,7 +2131,7 @@ static void Tst_ShowFormConfigTst (void)
HTM_TD_End ();
HTM_TD_Begin ("class=\"LB\"");
- TsV_PutVisibilityCheckboxes (Gbl.Test.Config.Visibility);
+ TsV_PutVisibilityCheckboxes (TstCfg_GetConfigVisibility ());
HTM_TD_End ();
HTM_TR_End ();
@@ -2050,254 +2176,6 @@ static void Tst_PutInputFieldNumQst (const char *Field,const char *Label,
HTM_TR_End ();
}
-/*****************************************************************************/
-/*************** Get configuration of test for current course ****************/
-/*****************************************************************************/
-
-void Tst_GetConfigTstFromDB (void)
- {
- MYSQL_RES *mysql_res;
- MYSQL_ROW row;
- unsigned long NumRows;
-
- /***** Get configuration of test for current course from database *****/
- NumRows = DB_QuerySELECT (&mysql_res,"can not get configuration of test",
- "SELECT Pluggable," // row[0]
- "Min," // row[1]
- "Def," // row[2]
- "Max," // row[3]
- "MinTimeNxtTstPerQst," // row[4]
- "Visibility" // row[5]
- " FROM tst_config"
- " WHERE CrsCod=%ld",
- Gbl.Hierarchy.Crs.CrsCod);
-
- Gbl.Test.Config.MinTimeNxtTstPerQst = 0UL;
- Gbl.Test.Config.Visibility = TsV_VISIBILITY_DEFAULT;
- if (NumRows == 0)
- {
- Gbl.Test.Config.Pluggable = Tst_PLUGGABLE_UNKNOWN;
- Gbl.Test.Config.Min = Tst_CONFIG_DEFAULT_MIN_QUESTIONS;
- Gbl.Test.Config.Def = Tst_CONFIG_DEFAULT_DEF_QUESTIONS;
- Gbl.Test.Config.Max = Tst_CONFIG_DEFAULT_MAX_QUESTIONS;
- }
- else // NumRows == 1
- {
- /***** Get minimun, default and maximum *****/
- row = mysql_fetch_row (mysql_res);
- Tst_GetConfigFromRow (row);
- }
-
- /***** Free structure that stores the query result *****/
- DB_FreeMySQLResult (&mysql_res);
- }
-
-/*****************************************************************************/
-/************ Get configuration values from a database table row *************/
-/*****************************************************************************/
-
-void Tst_GetConfigFromRow (MYSQL_ROW row)
- {
- int IntNum;
- long LongNum;
- Tst_Pluggable_t Pluggable;
-
- /***** Get whether test are visible via plugins or not *****/
- Gbl.Test.Config.Pluggable = Tst_PLUGGABLE_UNKNOWN;
- for (Pluggable = Tst_PLUGGABLE_NO;
- Pluggable <= Tst_PLUGGABLE_YES;
- Pluggable++)
- if (!strcmp (row[0],Tst_PluggableDB[Pluggable]))
- {
- Gbl.Test.Config.Pluggable = Pluggable;
- break;
- }
-
- /***** Get number of questions *****/
- if (sscanf (row[1],"%d",&IntNum) == 1)
- Gbl.Test.Config.Min = (IntNum < 1) ? 1 :
- (unsigned) IntNum;
- else
- Gbl.Test.Config.Min = Tst_CONFIG_DEFAULT_MIN_QUESTIONS;
-
- if (sscanf (row[2],"%d",&IntNum) == 1)
- Gbl.Test.Config.Def = (IntNum < 1) ? 1 :
- (unsigned) IntNum;
- else
- Gbl.Test.Config.Def = Tst_CONFIG_DEFAULT_DEF_QUESTIONS;
-
- if (sscanf (row[3],"%d",&IntNum) == 1)
- Gbl.Test.Config.Max = (IntNum < 1) ? 1 :
- (unsigned) IntNum;
- else
- Gbl.Test.Config.Max = Tst_CONFIG_DEFAULT_MAX_QUESTIONS;
-
- /***** Check and correct numbers *****/
- Tst_CheckAndCorrectNumbersQst ();
-
- /***** Get minimum time between consecutive tests, per question (row[4]) *****/
- if (sscanf (row[4],"%ld",&LongNum) == 1)
- Gbl.Test.Config.MinTimeNxtTstPerQst = (LongNum < 1L) ? 0UL :
- (unsigned long) LongNum;
-
- /***** Get visibility (row[5]) *****/
- Gbl.Test.Config.Visibility = TsV_GetVisibilityFromStr (row[5]);
- }
-
-/*****************************************************************************/
-/*************** Get configuration of test for current course ****************/
-/*****************************************************************************/
-// Returns true if course has test tags and pluggable is unknown
-// Return false if course has no test tags or pluggable is known
-
-bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void)
- {
- MYSQL_RES *mysql_res;
- MYSQL_ROW row;
- unsigned long NumRows;
- Tst_Pluggable_t Pluggable;
-
- /***** Get pluggability of tests for current course from database *****/
- NumRows = DB_QuerySELECT (&mysql_res,"can not get configuration of test",
- "SELECT Pluggable" // row[0]
- " FROM tst_config"
- " WHERE CrsCod=%ld",
- Gbl.Hierarchy.Crs.CrsCod);
-
- if (NumRows == 0)
- Gbl.Test.Config.Pluggable = Tst_PLUGGABLE_UNKNOWN;
- else // NumRows == 1
- {
- /***** Get whether test are visible via plugins or not *****/
- row = mysql_fetch_row (mysql_res);
-
- Gbl.Test.Config.Pluggable = Tst_PLUGGABLE_UNKNOWN;
- for (Pluggable = Tst_PLUGGABLE_NO;
- Pluggable <= Tst_PLUGGABLE_YES;
- Pluggable++)
- if (!strcmp (row[0],Tst_PluggableDB[Pluggable]))
- {
- Gbl.Test.Config.Pluggable = Pluggable;
- break;
- }
- }
-
- /***** Free structure that stores the query result *****/
- DB_FreeMySQLResult (&mysql_res);
-
- /***** Get if current course has tests from database *****/
- if (Gbl.Test.Config.Pluggable == Tst_PLUGGABLE_UNKNOWN)
- return Tst_CheckIfCurrentCrsHasTestTags (); // Return true if course has tests
-
- return false; // Pluggable is not unknown
- }
-
-/*****************************************************************************/
-/************* Receive configuration of test for current course **************/
-/*****************************************************************************/
-
-void Tst_ReceiveConfigTst (void)
- {
- extern const char *Txt_The_test_configuration_has_been_updated;
-
- /***** Get whether test are visible via plugins or not *****/
- Gbl.Test.Config.Pluggable = Tst_GetPluggableFromForm ();
-
- /***** Get number of questions *****/
- /* Get minimum number of questions */
- Gbl.Test.Config.Min = (unsigned)
- Par_GetParToUnsignedLong ("NumQstMin",
- 1,
- UINT_MAX,
- 1);
-
- /* Get default number of questions */
- Gbl.Test.Config.Def = (unsigned)
- Par_GetParToUnsignedLong ("NumQstDef",
- 1,
- UINT_MAX,
- 1);
-
- /* Get maximum number of questions */
- Gbl.Test.Config.Max = (unsigned)
- Par_GetParToUnsignedLong ("NumQstMax",
- 1,
- UINT_MAX,
- 1);
-
- /* Check and correct numbers */
- Tst_CheckAndCorrectNumbersQst ();
-
- /***** Get minimum time between consecutive tests, per question *****/
- Gbl.Test.Config.MinTimeNxtTstPerQst = Par_GetParToUnsignedLong ("MinTimeNxtTstPerQst",
- 0,
- ULONG_MAX,
- 0);
-
- /***** Get visibility from form *****/
- Gbl.Test.Config.Visibility = TsV_GetVisibilityFromForm ();
-
- /***** Update database *****/
- DB_QueryREPLACE ("can not save configuration of tests",
- "REPLACE INTO tst_config"
- " (CrsCod,Pluggable,Min,Def,Max,MinTimeNxtTstPerQst,Visibility)"
- " VALUES"
- " (%ld,'%s',%u,%u,%u,'%lu',%u)",
- Gbl.Hierarchy.Crs.CrsCod,
- Tst_PluggableDB[Gbl.Test.Config.Pluggable],
- Gbl.Test.Config.Min,Gbl.Test.Config.Def,Gbl.Test.Config.Max,
- Gbl.Test.Config.MinTimeNxtTstPerQst,
- Gbl.Test.Config.Visibility);
-
- /***** Show confirmation message *****/
- Ale_ShowAlert (Ale_SUCCESS,Txt_The_test_configuration_has_been_updated);
-
- /***** Show again the form to configure test *****/
- Tst_ShowFormConfig ();
- }
-
-/*****************************************************************************/
-/******************* Get if tests are pluggable from form ********************/
-/*****************************************************************************/
-
-static Tst_Pluggable_t Tst_GetPluggableFromForm (void)
- {
- return (Tst_Pluggable_t)
- Par_GetParToUnsignedLong ("Pluggable",
- 0,
- Tst_NUM_OPTIONS_PLUGGABLE - 1,
- (unsigned long) Tst_PLUGGABLE_UNKNOWN);
- }
-
-/*****************************************************************************/
-/**** Check and correct minimum, default and maximum numbers of questions ****/
-/*****************************************************************************/
-
-static void Tst_CheckAndCorrectNumbersQst (void)
- {
- /***** Check if minimum is correct *****/
- if (Gbl.Test.Config.Min < 1)
- Gbl.Test.Config.Min = 1;
- else if (Gbl.Test.Config.Min > Tst_MAX_QUESTIONS_PER_TEST)
- Gbl.Test.Config.Min = Tst_MAX_QUESTIONS_PER_TEST;
-
- /***** Check if maximum is correct *****/
- if (Gbl.Test.Config.Max < 1)
- Gbl.Test.Config.Max = 1;
- else if (Gbl.Test.Config.Max > Tst_MAX_QUESTIONS_PER_TEST)
- Gbl.Test.Config.Max = Tst_MAX_QUESTIONS_PER_TEST;
-
- /***** Check if minimum is lower than maximum *****/
- if (Gbl.Test.Config.Min > Gbl.Test.Config.Max)
- Gbl.Test.Config.Min = Gbl.Test.Config.Max;
-
- /***** Check if default is correct *****/
- if (Gbl.Test.Config.Def < Gbl.Test.Config.Min)
- Gbl.Test.Config.Def = Gbl.Test.Config.Min;
- else if (Gbl.Test.Config.Def > Gbl.Test.Config.Max)
- Gbl.Test.Config.Def = Gbl.Test.Config.Max;
- }
-
/*****************************************************************************/
/***************** Show form for select the types of answers *****************/
/*****************************************************************************/
@@ -2381,14 +2259,15 @@ static void Tst_ShowFormAnswerTypes (void)
void Tst_ListQuestionsToEdit (void)
{
+ struct Tst_Tags Tags;
MYSQL_RES *mysql_res;
unsigned long NumRows;
/***** Get parameters, query the database and list the questions *****/
- if (Tst_GetParamsTst (Tst_EDIT_TEST)) // Get parameters from the form
+ if (Tst_GetParamsTst (&Tags,Tst_EDIT_TEST)) // Get parameters from the form
{
/***** Get question codes from database *****/
- if ((NumRows = Tst_GetQuestions (&mysql_res)) != 0) // Query database
+ if ((NumRows = Tst_GetQuestions (&Tags,&mysql_res)) != 0) // Query database
{
/* Contextual menu */
Mnu_ContextMenuBegin ();
@@ -2397,11 +2276,11 @@ void Tst_ListQuestionsToEdit (void)
TsI_CreateXML (NumRows,mysql_res); // Create XML file with exported questions...
// ...and put a link to download it
else
- TsI_PutFormToExportQuestions (); // Export questions
+ TsI_PutFormToExportQuestions (&Tags); // Export questions
Mnu_ContextMenuEnd ();
/* Show the table with the questions */
- Tst_ListOneOrMoreQuestionsForEdition (NumRows,mysql_res);
+ Tst_ListOneOrMoreQuestionsForEdition (&Tags,NumRows,mysql_res);
}
/***** Free structure that stores the query result *****/
@@ -2409,10 +2288,10 @@ void Tst_ListQuestionsToEdit (void)
}
else
/* Show the form again */
- Tst_ShowFormAskEditTsts ();
+ Tst_ShowFormRequestEditTests (&Tags);
/***** Free memory used by the list of tags *****/
- Tst_FreeTagsList ();
+ Tst_FreeTagsList (&Tags);
}
/*****************************************************************************/
@@ -2421,13 +2300,14 @@ void Tst_ListQuestionsToEdit (void)
void Tst_ListQuestionsToSelect (void)
{
+ struct Tst_Tags Tags;
MYSQL_RES *mysql_res;
unsigned long NumRows;
/***** Get parameters, query the database and list the questions *****/
- if (Tst_GetParamsTst (Tst_SELECT_QUESTIONS_FOR_GAME)) // Get parameters from the form
+ if (Tst_GetParamsTst (&Tags,Tst_SELECT_QUESTIONS_FOR_GAME)) // Get parameters from the form
{
- if ((NumRows = Tst_GetQuestions (&mysql_res)) != 0) // Query database
+ if ((NumRows = Tst_GetQuestions (&Tags,&mysql_res)) != 0) // Query database
/* Show the table with the questions */
Tst_ListOneOrMoreQuestionsForSelection (NumRows,mysql_res);
@@ -2436,10 +2316,10 @@ void Tst_ListQuestionsToSelect (void)
}
else
/* Show the form again */
- Tst_ShowFormAskSelectTstsForGame ();
+ Tst_ShowFormRequestSelectTestsForGame (&Tags);
/***** Free memory used by the list of tags *****/
- Tst_FreeTagsList ();
+ Tst_FreeTagsList (&Tags);
}
/*****************************************************************************/
@@ -2448,7 +2328,8 @@ void Tst_ListQuestionsToSelect (void)
#define Tst_MAX_BYTES_QUERY_TEST (16 * 1024 - 1)
-static unsigned long Tst_GetQuestions (MYSQL_RES **mysql_res)
+static unsigned long Tst_GetQuestions (const struct Tst_Tags *Tags,
+ MYSQL_RES **mysql_res)
{
extern const char *Txt_No_questions_found_matching_your_search_criteria;
char *Query = NULL;
@@ -2471,7 +2352,7 @@ static unsigned long Tst_GetQuestions (MYSQL_RES **mysql_res)
snprintf (Query,Tst_MAX_BYTES_QUERY_TEST + 1,
"SELECT tst_questions.QstCod" // row[0]
" FROM tst_questions");
- if (!Gbl.Test.Tags.All)
+ if (!Tags->All)
Str_Concat (Query,",tst_question_tags,tst_tags",
Tst_MAX_BYTES_QUERY_TEST);
@@ -2500,7 +2381,7 @@ static unsigned long Tst_GetQuestions (MYSQL_RES **mysql_res)
Tst_MAX_BYTES_QUERY_TEST);
/* Add the tags selected */
- if (!Gbl.Test.Tags.All)
+ if (!Tags->All)
{
Str_Concat (Query," AND tst_questions.QstCod=tst_question_tags.QstCod"
" AND tst_question_tags.TagCod=tst_tags.TagCod"
@@ -2512,7 +2393,7 @@ static unsigned long Tst_GetQuestions (MYSQL_RES **mysql_res)
Tst_MAX_BYTES_QUERY_TEST);
LengthQuery = strlen (Query);
NumItemInList = 0;
- Ptr = Gbl.Test.Tags.List;
+ Ptr = Tags->List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tst_MAX_BYTES_TAG);
@@ -2609,7 +2490,8 @@ static unsigned long Tst_GetQuestions (MYSQL_RES **mysql_res)
/********* Get from the database several test questions to list them *********/
/*****************************************************************************/
-static unsigned long Tst_GetQuestionsForTest (MYSQL_RES **mysql_res)
+static unsigned long Tst_GetQuestionsForTest (const struct Tst_Tags *Tags,
+ MYSQL_RES **mysql_res)
{
char *Query = NULL;
long LengthQuery;
@@ -2645,12 +2527,12 @@ static unsigned long Tst_GetQuestionsForTest (MYSQL_RES **mysql_res)
Gbl.Hierarchy.Crs.CrsCod,
Gbl.Hierarchy.Crs.CrsCod);
- if (!Gbl.Test.Tags.All) // User has not selected all the tags
+ if (!Tags->All) // User has not selected all the tags
{
/* Add selected tags */
LengthQuery = strlen (Query);
NumItemInList = 0;
- Ptr = Gbl.Test.Tags.List;
+ Ptr = Tags->List;
while (*Ptr)
{
Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tst_MAX_BYTES_TAG);
@@ -2720,21 +2602,22 @@ static unsigned long Tst_GetQuestionsForTest (MYSQL_RES **mysql_res)
/*********************** List a test question for edition ********************/
/*****************************************************************************/
-static void Tst_ListOneQstToEdit (long QstCod)
+static void Tst_ListOneQstToEdit (long QstCod,const struct Tst_Tags *Tags)
{
extern const char *Hlp_ASSESSMENT_Tests;
extern const char *Txt_Questions;
/***** Begin box *****/
+ Tst_SetParamGblTags (Tags);
Box_BoxBegin (NULL,Txt_Questions,Tst_PutIconsTests,
Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE);
/***** Write the heading *****/
HTM_TABLE_BeginWideMarginPadding (2);
- Tst_WriteHeadingRowQuestionsForEdition (1);
+ Tst_WriteHeadingRowQuestionsForEdition (Tags,1);
/***** Write question row *****/
- Tst_WriteQuestionRowForEdition (1,0,QstCod);
+ Tst_WriteQuestionRowForEdition (Tags,1,0,QstCod);
/***** End table *****/
HTM_TABLE_End ();
@@ -2773,7 +2656,8 @@ bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res)
/****************** List for edition one or more test questions **************/
/*****************************************************************************/
-static void Tst_ListOneOrMoreQuestionsForEdition (unsigned long NumRows,
+static void Tst_ListOneOrMoreQuestionsForEdition (const struct Tst_Tags *Tags,
+ unsigned long NumRows,
MYSQL_RES *mysql_res)
{
extern const char *Hlp_ASSESSMENT_Tests;
@@ -2783,12 +2667,13 @@ static void Tst_ListOneOrMoreQuestionsForEdition (unsigned long NumRows,
long QstCod;
/***** Begin box *****/
+ Tst_SetParamGblTags (Tags);
Box_BoxBegin (NULL,Txt_Questions,Tst_PutIconsTests,
Hlp_ASSESSMENT_Tests,Box_NOT_CLOSABLE);
/***** Write the heading *****/
HTM_TABLE_BeginWideMarginPadding (2);
- Tst_WriteHeadingRowQuestionsForEdition (NumRows);
+ Tst_WriteHeadingRowQuestionsForEdition (Tags,NumRows);
/***** Write rows *****/
for (NumRow = 0;
@@ -2803,7 +2688,7 @@ static void Tst_ListOneOrMoreQuestionsForEdition (unsigned long NumRows,
Lay_ShowErrorAndExit ("Wrong code of question.");
/***** Write question row *****/
- Tst_WriteQuestionRowForEdition (NumRows,NumRow,QstCod);
+ Tst_WriteQuestionRowForEdition (Tags,NumRows,NumRow,QstCod);
}
/***** End table *****/
@@ -2820,7 +2705,8 @@ static void Tst_ListOneOrMoreQuestionsForEdition (unsigned long NumRows,
/*********** Write heading row in listing of questions for edition ***********/
/*****************************************************************************/
-static void Tst_WriteHeadingRowQuestionsForEdition (unsigned long NumRows)
+static void Tst_WriteHeadingRowQuestionsForEdition (const struct Tst_Tags *Tags,
+ unsigned long NumRows)
{
extern const char *Txt_No_INDEX;
extern const char *Txt_Code;
@@ -2856,6 +2742,7 @@ static void Tst_WriteHeadingRowQuestionsForEdition (unsigned long NumRows)
{
Frm_StartForm (ActLstTstQst);
Dat_WriteParamsIniEndDates ();
+ Tst_SetParamGblTags (Tags);
Tst_WriteParamEditQst ();
Par_PutHiddenParamUnsigned (NULL,"Order",(unsigned) Order);
HTM_BUTTON_SUBMIT_Begin (Txt_TST_STR_ORDER_FULL[Order],"BT_LINK TIT_TBL",NULL);
@@ -2882,7 +2769,8 @@ static void Tst_WriteHeadingRowQuestionsForEdition (unsigned long NumRows)
/********** Write question row in listing of questions for edition ***********/
/*****************************************************************************/
-static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
+static void Tst_WriteQuestionRowForEdition (const struct Tst_Tags *Tags,
+ unsigned long NumRows,
unsigned long NumRow,
long QstCod)
{
@@ -2929,6 +2817,7 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
if (NumRows == 1)
Par_PutHiddenParamChar ("OnlyThisQst",'Y'); // If there are only one row, don't list again after removing
Dat_WriteParamsIniEndDates ();
+ Tst_SetParamGblTags (Tags);
Tst_WriteParamEditQst ();
Ico_PutIconRemove ();
Frm_EndForm ();
@@ -2984,6 +2873,7 @@ static void Tst_WriteQuestionRowForEdition (unsigned long NumRows,
Frm_StartForm (ActChgShfTstQst);
Tst_PutParamQstCod (QstCod);
Dat_WriteParamsIniEndDates ();
+ Tst_SetParamGblTags (Tags);
Tst_WriteParamEditQst ();
if (NumRows == 1)
Par_PutHiddenParamChar ("OnlyThisQst",'Y'); // If editing only one question, don't edit others
@@ -3264,18 +3154,47 @@ static void Tst_WriteQuestionRowForSelection (unsigned long NumRow,long QstCod)
void Tst_WriteParamEditQst (void)
{
+ struct Tst_Tags Tags;
+
+ Tst_GetParamGblTags (&Tags);
Par_PutHiddenParamChar ("AllTags",
- Gbl.Test.Tags.All ? 'Y' :
- 'N');
+ Tags.All ? 'Y' :
+ 'N');
Par_PutHiddenParamString (NULL,"ChkTag",
- Gbl.Test.Tags.List ? Gbl.Test.Tags.List :
- "");
+ Tags.List ? Tags.List :
+ "");
+
Par_PutHiddenParamChar ("AllAnsTypes",
Gbl.Test.AllAnsTypes ? 'Y' :
'N');
Par_PutHiddenParamString (NULL,"AnswerType",Gbl.Test.ListAnsTypes);
}
+/*****************************************************************************/
+/************ Put parameter with question code to edit, remove... ************/
+/*****************************************************************************/
+
+void Tst_ResetGblTags (void)
+ {
+ Tst_ResetTags (&Tst_Test.Tags);
+ }
+
+void Tst_SetParamGblTags (const struct Tst_Tags *TagsSrc)
+ {
+ Tst_Test.Tags.Num = TagsSrc->Num;
+ Tst_Test.Tags.All = TagsSrc->All;
+ Tst_Test.Tags.List = TagsSrc->List;
+ /* It's not necessary to copy the Txt field */
+ }
+
+void Tst_GetParamGblTags (struct Tst_Tags *TagsDst)
+ {
+ TagsDst->Num = Tst_Test.Tags.Num;
+ TagsDst->All = Tst_Test.Tags.All;
+ TagsDst->List = Tst_Test.Tags.List;
+ /* It's not necessary to copy the Txt field */
+ }
+
/*****************************************************************************/
/*************** Get answers of a test question from database ****************/
/*****************************************************************************/
@@ -4069,7 +3988,7 @@ static void Tst_GetChoiceAns (MYSQL_RES *mysql_res,struct Tst_Question *Question
/***** Copy answer feedback (row[2]) and convert it,
that is in HTML, to rigorous HTML ******/
- if (TsV_IsVisibleFeedbackTxt (Gbl.Test.Config.Visibility))
+ if (TsV_IsVisibleFeedbackTxt (TstCfg_GetConfigVisibility ()))
if (row[2])
if (row[2][0])
{
@@ -4975,7 +4894,8 @@ void Tst_GetAndWriteTagsQst (long QstCod)
/*****************************************************************************/
// Return true (OK) if all parameters are found, or false (error) if any necessary parameter is not found
-static bool Tst_GetParamsTst (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions)
+static bool Tst_GetParamsTst (struct Tst_Tags *Tags,
+ Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions)
{
extern const char *Txt_You_must_select_one_ore_more_tags;
extern const char *Txt_You_must_select_one_ore_more_types_of_answer;
@@ -4986,16 +4906,16 @@ static bool Tst_GetParamsTst (Tst_ActionToDoWithQuestions_t ActionToDoWithQuesti
/***** Tags *****/
/* Get parameter that indicates whether all tags are selected */
- Gbl.Test.Tags.All = Par_GetParToBool ("AllTags");
+ Tags->All = Par_GetParToBool ("AllTags");
/* Get the tags */
- if ((Gbl.Test.Tags.List = (char *) malloc (Tst_MAX_BYTES_TAGS_LIST + 1)) == NULL)
+ if ((Tags->List = (char *) malloc (Tst_MAX_BYTES_TAGS_LIST + 1)) == NULL)
Lay_NotEnoughMemoryExit ();
- Par_GetParMultiToText ("ChkTag",Gbl.Test.Tags.List,Tst_MAX_BYTES_TAGS_LIST);
+ Par_GetParMultiToText ("ChkTag",Tags->List,Tst_MAX_BYTES_TAGS_LIST);
/* Check number of tags selected */
- if (Tst_CountNumTagsInList () == 0) // If no tags selected...
- { // ...write alert
+ if (Tst_CountNumTagsInList (Tags) == 0) // If no tags selected...
+ { // ...write alert
Ale_ShowAlert (Ale_WARNING,Txt_You_must_select_one_ore_more_tags);
Error = true;
}
@@ -5034,11 +4954,11 @@ static bool Tst_GetParamsTst (Tst_ActionToDoWithQuestions_t ActionToDoWithQuesti
{
case Tst_SHOW_TEST_TO_ANSWER:
Tst_GetParamNumQst ();
- if (Gbl.Test.NumQsts < Gbl.Test.Config.Min ||
- Gbl.Test.NumQsts > Gbl.Test.Config.Max)
+ if (Gbl.Test.NumQsts < TstCfg_GetConfigMin () ||
+ Gbl.Test.NumQsts > TstCfg_GetConfigMax ())
{
Ale_ShowAlert (Ale_WARNING,Txt_The_number_of_questions_must_be_in_the_interval_X,
- Gbl.Test.Config.Min,Gbl.Test.Config.Max);
+ TstCfg_GetConfigMin (),TstCfg_GetConfigMax ());
Error = true;
}
break;
@@ -5091,31 +5011,29 @@ static void Tst_GetParamNumQst (void)
{
Gbl.Test.NumQsts = (unsigned)
Par_GetParToUnsignedLong ("NumQst",
- (unsigned long) Gbl.Test.Config.Min,
- (unsigned long) Gbl.Test.Config.Max,
- (unsigned long) Gbl.Test.Config.Def);
+ (unsigned long) TstCfg_GetConfigMin (),
+ (unsigned long) TstCfg_GetConfigMax (),
+ (unsigned long) TstCfg_GetConfigDef ());
}
/*****************************************************************************/
/***************** Count number of tags in the list of tags ******************/
/*****************************************************************************/
-static int Tst_CountNumTagsInList (void)
+static unsigned Tst_CountNumTagsInList (const struct Tst_Tags *Tags)
{
const char *Ptr;
- int NumTags = 0;
+ unsigned NumTags = 0;
char TagText[Tst_MAX_BYTES_TAG + 1];
- /***** Go over the list Gbl.Test.Tags.List counting the number of tags *****/
- if (Gbl.Test.Tags.List)
+ /***** Go over the list of tags counting the number of tags *****/
+ Ptr = Tags->List;
+ while (*Ptr)
{
- Ptr = Gbl.Test.Tags.List;
- while (*Ptr)
- {
- Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tst_MAX_BYTES_TAG);
- NumTags++;
- }
+ Par_GetNextStrUntilSeparParamMult (&Ptr,TagText,Tst_MAX_BYTES_TAG);
+ NumTags++;
}
+
return NumTags;
}
@@ -5144,13 +5062,12 @@ static int Tst_CountNumAnswerTypesInList (void)
/**************** Free memory allocated for the list of tags *****************/
/*****************************************************************************/
-void Tst_FreeTagsList (void)
+static void Tst_FreeTagsList (struct Tst_Tags *Tags)
{
- if (Gbl.Test.Tags.List)
+ if (Tags->List)
{
- free (Gbl.Test.Tags.List);
- Gbl.Test.Tags.List = NULL;
- Gbl.Test.Tags.Num = 0;
+ free (Tags->List);
+ Tst_ResetTags (Tags);
}
}
@@ -5162,22 +5079,25 @@ void Tst_ShowFormEditOneQst (void)
{
long QstCod;
struct Tst_Question Question;
+ struct Tst_Tags Tags;
char Stem[Cns_MAX_BYTES_TEXT + 1];
char Feedback[Cns_MAX_BYTES_TEXT + 1];
/***** Create test question *****/
Tst_QstConstructor (&Question);
+ Tst_ResetTags (&Tags);
/***** Get question data *****/
QstCod = Tst_GetQstCod ();
Stem[0] = Feedback[0] = '\0';
if (QstCod > 0) // If question already exists in the database
- Tst_GetQstDataFromDB (QstCod,&Question,Stem,Feedback);
+ Tst_GetQstDataFromDB (QstCod,&Question,&Tags,Stem,Feedback);
/***** Put form to edit question *****/
- Tst_PutFormEditOneQst (QstCod,&Question,Stem,Feedback);
+ Tst_PutFormEditOneQst (QstCod,&Question,&Tags,Stem,Feedback);
/***** Destroy test question *****/
+ Tst_FreeTagsList (&Tags);
Tst_QstDestructor (&Question);
}
@@ -5192,6 +5112,7 @@ void Tst_ShowFormEditOneQst (void)
static void Tst_PutFormEditOneQst (long QstCod,
const struct Tst_Question *Question,
+ const struct Tst_Tags *Tags,
char Stem[Cns_MAX_BYTES_TEXT + 1],
char Feedback[Cns_MAX_BYTES_TEXT + 1])
{
@@ -5299,7 +5220,7 @@ static void Tst_PutFormEditOneQst (long QstCod,
row[2] TagHidden
*/
IsThisTag = false;
- if (!strcasecmp (Gbl.Test.Tags.Txt[NumTag],row[1]))
+ if (!strcasecmp (Tags->Txt[NumTag],row[1]))
{
HTM_Txt (" selected=\"selected\"");
IsThisTag = true;
@@ -5310,10 +5231,10 @@ static void Tst_PutFormEditOneQst (long QstCod,
"%s",row[1]);
}
/* If it's a new tag received from the form */
- if (!TagFound && Gbl.Test.Tags.Txt[NumTag][0])
- HTM_OPTION (HTM_Type_STRING,Gbl.Test.Tags.Txt[NumTag],
+ if (!TagFound && Tags->Txt[NumTag][0])
+ HTM_OPTION (HTM_Type_STRING,Tags->Txt[NumTag],
true,false,
- "%s",Gbl.Test.Tags.Txt[NumTag]);
+ "%s",Tags->Txt[NumTag]);
HTM_OPTION (HTM_Type_STRING,"",
false,false,
"[%s]",Txt_new_tag);
@@ -5325,7 +5246,7 @@ static void Tst_PutFormEditOneQst (long QstCod,
snprintf (StrTagTxt,sizeof (StrTagTxt),
"TagTxt%u",
NumTag);
- HTM_INPUT_TEXT (StrTagTxt,Tst_MAX_CHARS_TAG,Gbl.Test.Tags.Txt[NumTag],false,
+ HTM_INPUT_TEXT (StrTagTxt,Tst_MAX_CHARS_TAG,Tags->Txt[NumTag],false,
"id=\"%s\" class=\"TAG_TXT\" onchange=\"changeSelTag('%u')\"",
StrTagTxt,NumTag);
HTM_TD_End ();
@@ -5792,6 +5713,7 @@ static void Tst_FreeMediaOfQuestion (struct Tst_Question *Question)
static void Tst_GetQstDataFromDB (long QstCod,
struct Tst_Question *Question,
+ struct Tst_Tags *Tags,
char Stem[Cns_MAX_BYTES_TEXT + 1],
char Feedback[Cns_MAX_BYTES_TEXT + 1])
{
@@ -5845,7 +5767,7 @@ static void Tst_GetQstDataFromDB (long QstCod,
NumRow++)
{
row = mysql_fetch_row (mysql_res);
- Str_Copy (Gbl.Test.Tags.Txt[NumRow],row[0],
+ Str_Copy (Tags->Txt[NumRow],row[0],
Tst_MAX_BYTES_TAG);
}
@@ -6022,27 +5944,29 @@ void Tst_ReceiveQst (void)
{
long QstCod;
struct Tst_Question Question;
+ struct Tst_Tags Tags;
char Stem[Cns_MAX_BYTES_TEXT + 1];
char Feedback[Cns_MAX_BYTES_TEXT + 1];
/***** Create test question *****/
Tst_QstConstructor (&Question);
+ Tst_ResetTags (&Tags);
/***** Get parameters of the question from form *****/
Stem[0] = Feedback[0] = '\0';
- QstCod = Tst_GetQstFromForm (&Question,Stem,Feedback);
+ QstCod = Tst_GetQstFromForm (&Question,&Tags,Stem,Feedback);
/***** Make sure that tags, text and answer are not empty *****/
- if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question))
+ if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question,&Tags))
{
/***** Move images to definitive directories *****/
Tst_MoveMediaToDefinitiveDirectories (QstCod,&Question);
/***** Insert or update question, tags and answer in the database *****/
- QstCod = Tst_InsertOrUpdateQstTagsAnsIntoDB (QstCod,&Question);
+ QstCod = Tst_InsertOrUpdateQstTagsAnsIntoDB (QstCod,&Question,&Tags);
/***** Show the question just inserted in the database *****/
- Tst_ListOneQstToEdit (QstCod);
+ Tst_ListOneQstToEdit (QstCod,&Tags);
}
else // Question is wrong
{
@@ -6050,10 +5974,11 @@ void Tst_ReceiveQst (void)
Tst_ResetMediaOfQuestion (&Question);
/***** Put form to edit question again *****/
- Tst_PutFormEditOneQst (QstCod,&Question,Stem,Feedback);
+ Tst_PutFormEditOneQst (QstCod,&Question,&Tags,Stem,Feedback);
}
/***** Destroy test question *****/
+ Tst_FreeTagsList (&Tags);
Tst_QstDestructor (&Question);
}
@@ -6062,6 +5987,7 @@ void Tst_ReceiveQst (void)
/*****************************************************************************/
static long Tst_GetQstFromForm (struct Tst_Question *Question,
+ struct Tst_Tags *Tags,
char *Stem,char *Feedback)
{
long QstCod;
@@ -6097,19 +6023,19 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question,
snprintf (TagStr,sizeof (TagStr),
"TagTxt%u",
NumTag);
- Par_GetParToText (TagStr,Gbl.Test.Tags.Txt[NumTag],Tst_MAX_BYTES_TAG);
+ Par_GetParToText (TagStr,Tags->Txt[NumTag],Tst_MAX_BYTES_TAG);
- if (Gbl.Test.Tags.Txt[NumTag][0])
+ if (Tags->Txt[NumTag][0])
{
Str_ChangeFormat (Str_FROM_FORM,Str_TO_TEXT,
- Gbl.Test.Tags.Txt[NumTag],Tst_MAX_BYTES_TAG,true);
+ Tags->Txt[NumTag],Tst_MAX_BYTES_TAG,true);
/* Check if not repeated */
for (NumTagRead = 0;
NumTagRead < NumTag;
NumTagRead++)
- if (!strcmp (Gbl.Test.Tags.Txt[NumTagRead],Gbl.Test.Tags.Txt[NumTag]))
+ if (!strcmp (Tags->Txt[NumTagRead],Tags->Txt[NumTag]))
{
- Gbl.Test.Tags.Txt[NumTag][0] = '\0';
+ Tags->Txt[NumTag][0] = '\0';
break;
}
}
@@ -6247,12 +6173,12 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question,
break;
}
- /***** Adjust global variables related to this test question *****/
- for (NumTag = 0, Gbl.Test.Tags.Num = 0;
+ /***** Adjust variables related to this test question *****/
+ for (NumTag = 0, Tags->Num = 0;
NumTag < Tst_MAX_TAGS_PER_QUESTION;
NumTag++)
- if (Gbl.Test.Tags.Txt[NumTag][0])
- Gbl.Test.Tags.Num++;
+ if (Tags->Txt[NumTag][0])
+ Tags->Num++;
Question->Stem.Text = Stem;
Question->Stem.Length = strlen (Question->Stem.Text);
Question->Feedback.Text = Feedback;
@@ -6268,7 +6194,8 @@ static long Tst_GetQstFromForm (struct Tst_Question *Question,
// Counts Question->Answer.NumOptions
// Computes Question->Answer.Integer and Question->Answer.FloatingPoint[0..1]
-bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Question)
+bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Question,
+ const struct Tst_Tags *Tags)
{
extern const char *Txt_You_must_type_at_least_one_tag_for_the_question;
extern const char *Txt_You_must_type_the_stem_of_the_question;
@@ -6289,7 +6216,7 @@ bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Quest
Question->Answer.NumOptions = 0;
/***** A question must have at least one tag *****/
- if (!Gbl.Test.Tags.Num) // There are no tags with text
+ if (!Tags->Num) // There are no tags with text
{
Ale_ShowAlert (Ale_WARNING,Txt_You_must_type_at_least_one_tag_for_the_question);
return false;
@@ -6684,19 +6611,23 @@ void Tst_RequestRemoveSelectedQsts (void)
{
extern const char *Txt_Do_you_really_want_to_remove_the_selected_questions;
extern const char *Txt_Remove_questions;
+ struct Tst_Tags Tags;
/***** Get parameters *****/
- if (Tst_GetParamsTst (Tst_EDIT_TEST)) // Get parameters from the form
+ if (Tst_GetParamsTst (&Tags,Tst_EDIT_TEST)) // Get parameters from the form
+ {
/***** Show question and button to remove question *****/
+ Tst_SetParamGblTags (&Tags);
Ale_ShowAlertAndButton (ActRemSevTstQst,NULL,NULL,
Tst_PutParamsRemoveSelectedQsts,
Btn_REMOVE_BUTTON,Txt_Remove_questions,
Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_selected_questions);
+ }
else
Ale_ShowAlert (Ale_ERROR,"Wrong parameters.");
/***** Free memory used by the list of tags *****/
- Tst_FreeTagsList ();
+ Tst_FreeTagsList (&Tags);
/***** Continue editing questions *****/
Tst_ListQuestionsToEdit ();
@@ -6719,6 +6650,7 @@ static void Tst_PutParamsRemoveSelectedQsts (void)
void Tst_RemoveSelectedQsts (void)
{
extern const char *Txt_Questions_removed_X;
+ struct Tst_Tags Tags;
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRows;
@@ -6726,10 +6658,10 @@ void Tst_RemoveSelectedQsts (void)
long QstCod;
/***** Get parameters *****/
- if (Tst_GetParamsTst (Tst_EDIT_TEST)) // Get parameters
+ if (Tst_GetParamsTst (&Tags,Tst_EDIT_TEST)) // Get parameters
{
/***** Get question codes *****/
- NumRows = (unsigned) Tst_GetQuestions (&mysql_res); // Query database
+ NumRows = (unsigned) Tst_GetQuestions (&Tags,&mysql_res); // Query database
/***** Remove questions one by one *****/
for (NumRow = 0;
@@ -6772,6 +6704,7 @@ void Tst_RequestRemoveOneQst (void)
extern const char *Txt_Remove_question;
long QstCod;
bool EditingOnlyThisQst;
+ struct Tst_Tags Tags;
/***** Get main parameters from form *****/
/* Get the question code */
@@ -6785,11 +6718,12 @@ void Tst_RequestRemoveOneQst (void)
/* Get other parameters */
if (!EditingOnlyThisQst)
- if (!Tst_GetParamsTst (Tst_EDIT_TEST))
+ if (!Tst_GetParamsTst (&Tags,Tst_EDIT_TEST))
Lay_ShowErrorAndExit ("Wrong test parameters.");
/***** Show question and button to remove question *****/
Tst_SetParamGblQstCod (QstCod);
+ Tst_SetParamGblTags (&Tags);
Ale_ShowAlertAndButton (ActRemOneTstQst,NULL,NULL,
EditingOnlyThisQst ? Tst_PutParamsRemoveOnlyThisQst :
Tst_PutParamsRemoveOneQstWhileEditing,
@@ -6799,10 +6733,10 @@ void Tst_RequestRemoveOneQst (void)
/***** Continue editing questions *****/
if (EditingOnlyThisQst)
- Tst_ListOneQstToEdit (QstCod);
+ Tst_ListOneQstToEdit (QstCod,&Tags);
else
{
- Tst_FreeTagsList ();
+ Tst_FreeTagsList (&Tags);
Tst_ListQuestionsToEdit ();
}
}
@@ -6902,6 +6836,7 @@ void Tst_ChangeShuffleQst (void)
long QstCod;
bool EditingOnlyThisQst;
bool Shuffle;
+ struct Tst_Tags Tags;
/***** Get the question code *****/
QstCod = Tst_GetQstCod ();
@@ -6930,7 +6865,10 @@ void Tst_ChangeShuffleQst (void)
/***** Continue editing questions *****/
if (EditingOnlyThisQst)
- Tst_ListOneQstToEdit (QstCod);
+ {
+ Tst_ResetTags (&Tags);
+ Tst_ListOneQstToEdit (QstCod,&Tags);
+ }
else
Tst_ListQuestionsToEdit ();
}
@@ -6974,14 +6912,15 @@ void Tst_PutParamQstCod (long QstCod)
/*****************************************************************************/
long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod,
- struct Tst_Question *Question)
+ struct Tst_Question *Question,
+ const struct Tst_Tags *Tags)
{
/***** Insert or update question in the table of questions *****/
QstCod = Tst_InsertOrUpdateQstIntoDB (QstCod,Question);
if (QstCod > 0)
{
/***** Insert tags in the tags table *****/
- Tst_InsertTagsIntoDB (QstCod);
+ Tst_InsertTagsIntoDB (QstCod,Tags);
/***** Remove unused tags in current course *****/
Tst_RemoveUnusedTagsFromCrs (Gbl.Hierarchy.Crs.CrsCod);
@@ -7068,7 +7007,7 @@ static long Tst_InsertOrUpdateQstIntoDB (long QstCod,
/*********************** Insert tags in the tags table ***********************/
/*****************************************************************************/
-static void Tst_InsertTagsIntoDB (long QstCod)
+static void Tst_InsertTagsIntoDB (long QstCod,const struct Tst_Tags *Tags)
{
unsigned NumTag;
unsigned TagIdx;
@@ -7076,14 +7015,14 @@ static void Tst_InsertTagsIntoDB (long QstCod)
/***** For each tag... *****/
for (NumTag = 0, TagIdx = 0;
- TagIdx < Gbl.Test.Tags.Num;
+ TagIdx < Tags->Num;
NumTag++)
- if (Gbl.Test.Tags.Txt[NumTag][0])
+ if (Tags->Txt[NumTag][0])
{
/***** Check if this tag exists for current course *****/
- if ((TagCod = Tst_GetTagCodFromTagTxt (Gbl.Test.Tags.Txt[NumTag])) < 0)
+ if ((TagCod = Tst_GetTagCodFromTagTxt (Tags->Txt[NumTag])) < 0)
/* This tag is new for current course. Add it to tags table */
- TagCod = Tst_CreateNewTag (Gbl.Hierarchy.Crs.CrsCod,Gbl.Test.Tags.Txt[NumTag]);
+ TagCod = Tst_CreateNewTag (Gbl.Hierarchy.Crs.CrsCod,Tags->Txt[NumTag]);
/***** Insert tag in tst_question_tags *****/
DB_QueryINSERT ("can not create tag",
@@ -7688,6 +7627,7 @@ static unsigned Tst_GetNumCoursesWithTstQuestions (Hie_Level_t Scope,Tst_AnswerT
static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Tst_AnswerType_t AnsType)
{
+ extern const char *TstCfg_PluggableDB[TstCfg_NUM_OPTIONS_PLUGGABLE];
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumCourses;
@@ -7703,7 +7643,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" FROM tst_questions,tst_config"
" WHERE tst_questions.CrsCod=tst_config.CrsCod"
" AND tst_config.pluggable='%s'",
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
else
DB_QuerySELECT (&mysql_res,"can not get number of courses"
" with pluggable test questions",
@@ -7713,7 +7653,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_questions.CrsCod=tst_config.CrsCod"
" AND tst_config.pluggable='%s'",
Tst_StrAnswerTypesDB[AnsType],
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
break;
case Hie_CTY:
if (AnsType == Tst_ANS_ALL)
@@ -7729,7 +7669,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_questions.CrsCod=tst_config.CrsCod"
" AND tst_config.pluggable='%s'",
Gbl.Hierarchy.Cty.CtyCod,
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
else
DB_QuerySELECT (&mysql_res,"can not get number of courses"
" with pluggable test questions",
@@ -7745,7 +7685,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_config.pluggable='%s'",
Gbl.Hierarchy.Cty.CtyCod,
Tst_StrAnswerTypesDB[AnsType],
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
break;
case Hie_INS:
if (AnsType == Tst_ANS_ALL)
@@ -7760,7 +7700,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_questions.CrsCod=tst_config.CrsCod"
" AND tst_config.pluggable='%s'",
Gbl.Hierarchy.Ins.InsCod,
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
else
DB_QuerySELECT (&mysql_res,"can not get number of courses"
" with pluggable test questions",
@@ -7775,7 +7715,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_config.pluggable='%s'",
Gbl.Hierarchy.Ins.InsCod,
Tst_StrAnswerTypesDB[AnsType],
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
break;
case Hie_CTR:
if (AnsType == Tst_ANS_ALL)
@@ -7789,7 +7729,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_questions.CrsCod=tst_config.CrsCod"
" AND tst_config.pluggable='%s'",
Gbl.Hierarchy.Ctr.CtrCod,
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
else
DB_QuerySELECT (&mysql_res,"can not get number of courses"
" with pluggable test questions",
@@ -7803,7 +7743,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_config.pluggable='%s'",
Gbl.Hierarchy.Ctr.CtrCod,
Tst_StrAnswerTypesDB[AnsType],
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
break;
case Hie_DEG:
if (AnsType == Tst_ANS_ALL)
@@ -7816,7 +7756,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_questions.CrsCod=tst_config.CrsCod"
" AND tst_config.pluggable='%s'",
Gbl.Hierarchy.Deg.DegCod,
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
else
DB_QuerySELECT (&mysql_res,"can not get number of courses"
" with pluggable test questions",
@@ -7829,7 +7769,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_config.pluggable='%s'",
Gbl.Hierarchy.Deg.DegCod,
Tst_StrAnswerTypesDB[AnsType],
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
break;
case Hie_CRS:
if (AnsType == Tst_ANS_ALL)
@@ -7841,7 +7781,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_questions.CrsCod=tst_config.CrsCod"
" AND tst_config.pluggable='%s'",
Gbl.Hierarchy.Crs.CrsCod,
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
else
DB_QuerySELECT (&mysql_res,"can not get number of courses"
" with pluggable test questions",
@@ -7853,7 +7793,7 @@ static unsigned Tst_GetNumCoursesWithPluggableTstQuestions (Hie_Level_t Scope,Ts
" AND tst_config.pluggable='%s'",
Gbl.Hierarchy.Crs.CrsCod,
Tst_StrAnswerTypesDB[AnsType],
- Tst_PluggableDB[Tst_PLUGGABLE_YES]);
+ TstCfg_PluggableDB[TstCfg_PLUGGABLE_YES]);
break;
default:
Lay_WrongScopeExit ();
diff --git a/swad_test.h b/swad_test.h
index 8b930244..ea4c382e 100644
--- a/swad_test.h
+++ b/swad_test.h
@@ -29,13 +29,13 @@
#include "swad_game.h"
#include "swad_media.h"
+#include "swad_test_config.h"
#include "swad_test_result.h"
/*****************************************************************************/
/***************************** Public constants ******************************/
/*****************************************************************************/
-#define Tst_MAX_QUESTIONS_PER_TEST 100 // Absolute maximum number of questions in a test
#define Tst_MAX_TAGS_PER_QUESTION 5
#define Tst_MAX_CHARS_TAG (128 - 1) // 127
@@ -48,16 +48,20 @@
#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_CONFIG_DEFAULT_MIN_QUESTIONS 1
-#define Tst_CONFIG_DEFAULT_DEF_QUESTIONS 20 // Number of questions to be generated by default in a self-assessment test
-#define Tst_CONFIG_DEFAULT_MAX_QUESTIONS 30 // Maximum number of questions to be generated in a self-assessment test
-
#define Tst_MAX_BYTES_ANSWER_TYPE 32
/*****************************************************************************/
/******************************* 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
@@ -71,6 +75,29 @@ typedef enum
Tst_ANS_ALL = 6, // All/any type of answer
} Tst_AnswerType_t;
+#define Tst_NUM_TYPES_ORDER_QST 5
+typedef enum
+ {
+ Tst_ORDER_STEM = 0,
+ Tst_ORDER_NUM_HITS = 1,
+ Tst_ORDER_AVERAGE_SCORE = 2,
+ Tst_ORDER_NUM_HITS_NOT_BLANK = 3,
+ Tst_ORDER_AVERAGE_SCORE_NOT_BLANK = 4,
+ } Tst_QuestionsOrder_t;
+
+struct Tst_Test
+ {
+ struct Tst_Tags Tags;
+ unsigned NumQsts;
+ long QstCodes[TstCfg_MAX_QUESTIONS_PER_TEST]; // Codes of the sent/received questions in a test
+ char StrIndexesOneQst[TstCfg_MAX_QUESTIONS_PER_TEST][Tst_MAX_BYTES_INDEXES_ONE_QST + 1]; // 0 1 2 3, 3 0 2 1, etc.
+ char StrAnswersOneQst[TstCfg_MAX_QUESTIONS_PER_TEST][Tst_MAX_BYTES_ANSWERS_ONE_QST + 1]; // Answers selected by user
+ bool AllowTeachers; // Can teachers of this course see the test result?
+ bool AllAnsTypes;
+ char ListAnsTypes[Tst_MAX_BYTES_LIST_ANSWER_TYPES + 1];
+ Tst_QuestionsOrder_t SelectedOrder;
+ };
+
struct Tst_Question
{
struct
@@ -97,14 +124,6 @@ struct Tst_Question
} Answer;
};
-#define Tst_NUM_OPTIONS_PLUGGABLE 3
-typedef enum
- {
- Tst_PLUGGABLE_UNKNOWN = 0,
- Tst_PLUGGABLE_NO = 1,
- Tst_PLUGGABLE_YES = 2,
- } Tst_Pluggable_t;
-
typedef enum
{
Tst_SHOW_TEST_TO_ANSWER, // Showing a test to a student
@@ -113,26 +132,6 @@ typedef enum
Tst_SELECT_QUESTIONS_FOR_GAME, // Selecting test questions for a game
} Tst_ActionToDoWithQuestions_t;
-struct Tst_Config
- {
- Tst_Pluggable_t Pluggable;
- unsigned Min; // Minimum number of questions
- unsigned Def; // Default number of questions
- unsigned Max; // Maximum number of questions
- unsigned long MinTimeNxtTstPerQst;
- unsigned Visibility; // One bit for each visibility item
- };
-
-#define Tst_NUM_TYPES_ORDER_QST 5
-typedef enum
- {
- Tst_ORDER_STEM = 0,
- Tst_ORDER_NUM_HITS = 1,
- Tst_ORDER_AVERAGE_SCORE = 2,
- Tst_ORDER_NUM_HITS_NOT_BLANK = 3,
- Tst_ORDER_AVERAGE_SCORE_NOT_BLANK = 4,
- } Tst_QuestionsOrder_t;
-
struct Tst_Stats
{
unsigned NumCoursesWithQuestions;
@@ -150,7 +149,7 @@ struct Tst_Stats
/***************************** Public prototypes *****************************/
/*****************************************************************************/
-void Tst_ShowFormAskTst (void);
+void Tst_RequestTest (void);
void Tst_ShowNewTest (void);
void Tst_AssessTest (void);
@@ -170,12 +169,18 @@ void Tst_WriteQstAndAnsTest (Tst_ActionToDoWithQuestions_t ActionToDoWithQuestio
void Tst_WriteQstStem (const char *Stem,const char *ClassStem,bool Visible);
void Tst_WriteQstFeedback (const char *Feedback,const char *ClassFeedback);
-void Tst_ShowFormAskEditTsts (void);
-void Tst_ShowFormAskSelectTstsForGame (void);
+void Tst_RequestEditTests (void);
+void Tst_RequestSelectTestsForGame (void);
+
void Tst_ListQuestionsToEdit (void);
void Tst_ListQuestionsToSelect (void);
bool Tst_GetOneQuestionByCod (long QstCod,MYSQL_RES **mysql_res);
void Tst_WriteParamEditQst (void);
+
+void Tst_ResetGblTags (void);
+void Tst_SetParamGblTags (const struct Tst_Tags *TagsSrc);
+void Tst_GetParamGblTags (struct Tst_Tags *TagsDst);
+
unsigned Tst_GetNumAnswersQst (long QstCod);
unsigned Tst_GetAnswersQst (long QstCod,MYSQL_RES **mysql_res,bool Shuffle);
void Tst_GetCorrectAnswersFromDB (long QstCod,struct Tst_Question *Question);
@@ -196,18 +201,14 @@ void Tst_CheckIfNumberOfAnswersIsOne (const struct Tst_Question *Question);
unsigned long Tst_GetTagsQst (long QstCod,MYSQL_RES **mysql_res);
void Tst_GetAndWriteTagsQst (long QstCod);
-void Tst_FreeTagsList (void);
void Tst_ShowFormConfig (void);
void Tst_EnableTag (void);
void Tst_DisableTag (void);
void Tst_RenameTag (void);
-void Tst_GetConfigTstFromDB (void);
-
-void Tst_GetConfigFromRow (MYSQL_ROW row);
bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void);
-void Tst_ReceiveConfigTst (void);
+
void Tst_ShowFormEditOneQst (void);
void Tst_QstConstructor (struct Tst_Question *Question);
@@ -217,7 +218,8 @@ int Tst_AllocateTextChoiceAnswer (struct Tst_Question *Question,unsigned NumOpt)
Tst_AnswerType_t Tst_ConvertFromStrAnsTypDBToAnsTyp (const char *StrAnsTypeBD);
void Tst_ReceiveQst (void);
-bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Question);
+bool Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (struct Tst_Question *Question,
+ const struct Tst_Tags *Tags);
bool Tst_CheckIfQuestionExistsInDB (const struct Tst_Question *Question);
@@ -236,7 +238,8 @@ void Tst_PutParamGblQstCod (void);
void Tst_PutParamQstCod (long QstCod);
long Tst_InsertOrUpdateQstTagsAnsIntoDB (long QstCod,
- struct Tst_Question *Question);
+ struct Tst_Question *Question,
+ const struct Tst_Tags *Tags);
void Tst_RemoveCrsTests (long CrsCod);
diff --git a/swad_test_config.c b/swad_test_config.c
new file mode 100644
index 00000000..cf0be028
--- /dev/null
+++ b/swad_test_config.c
@@ -0,0 +1,373 @@
+// swad_test_config.c: self-assessment tests configuration
+
+/*
+ SWAD (Shared Workspace At a Distance),
+ 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 .
+*/
+/*****************************************************************************/
+/*********************************** Headers *********************************/
+/*****************************************************************************/
+
+// #define _GNU_SOURCE // For asprintf
+// #include // For UINT_MAX
+// #include // For PATH_MAX
+// #include // To access MySQL databases
+// #include // For boolean type
+// #include // For NULL
+// #include // For asprintf
+// #include // For exit, system, malloc, free, etc
+#include // For string functions
+// #include // For mkdir
+// #include // For mkdir
+
+// #include "swad_action.h"
+// #include "swad_box.h"
+#include "swad_database.h"
+// #include "swad_form.h"
+#include "swad_global.h"
+// #include "swad_HTML.h"
+// #include "swad_ID.h"
+// #include "swad_language.h"
+// #include "swad_match.h"
+// #include "swad_media.h"
+// #include "swad_parameter.h"
+// #include "swad_theme.h"
+// #include "swad_test.h"
+#include "swad_test_config.h"
+// #include "swad_test_import.h"
+#include "swad_test_visibility.h"
+// #include "swad_user.h"
+// #include "swad_xml.h"
+
+/*****************************************************************************/
+/***************************** Public constants ******************************/
+/*****************************************************************************/
+
+const char *TstCfg_PluggableDB[TstCfg_NUM_OPTIONS_PLUGGABLE] =
+ {
+ [TstCfg_PLUGGABLE_UNKNOWN] = "unknown",
+ [TstCfg_PLUGGABLE_NO ] = "N",
+ [TstCfg_PLUGGABLE_YES ] = "Y",
+ };
+
+/*****************************************************************************/
+/**************************** Private constants ******************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/******************************* Private types *******************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/************** External global variables from others modules ****************/
+/*****************************************************************************/
+
+extern struct Globals Gbl;
+
+/*****************************************************************************/
+/************************* Private global variables **************************/
+/*****************************************************************************/
+
+struct TstCfg_Config
+ {
+ TstCfg_Pluggable_t Pluggable;
+ unsigned Min; // Minimum number of questions
+ unsigned Def; // Default number of questions
+ unsigned Max; // Maximum number of questions
+ unsigned long MinTimeNxtTstPerQst;
+ unsigned Visibility; // One bit for each visibility item
+ };
+
+struct TstCfg_Config TstCfg_Config;
+
+/*****************************************************************************/
+/***************************** Private prototypes ****************************/
+/*****************************************************************************/
+
+static TstCfg_Pluggable_t TstCfg_GetPluggableFromForm (void);
+static void TstCfg_CheckAndCorrectMinDefMax (void);
+
+/*****************************************************************************/
+/*************** Get configuration of test for current course ****************/
+/*****************************************************************************/
+
+void TstCfg_GetConfigFromDB (void)
+ {
+ MYSQL_RES *mysql_res;
+ MYSQL_ROW row;
+ unsigned long NumRows;
+
+ /***** Get configuration of test for current course from database *****/
+ NumRows = DB_QuerySELECT (&mysql_res,"can not get configuration of test",
+ "SELECT Pluggable," // row[0]
+ "Min," // row[1]
+ "Def," // row[2]
+ "Max," // row[3]
+ "MinTimeNxtTstPerQst," // row[4]
+ "Visibility" // row[5]
+ " FROM tst_config"
+ " WHERE CrsCod=%ld",
+ Gbl.Hierarchy.Crs.CrsCod);
+
+ TstCfg_SetConfigMinTimeNxtTstPerQst (0UL);
+ TstCfg_SetConfigVisibility (TsV_VISIBILITY_DEFAULT);
+ if (NumRows == 0)
+ {
+ TstCfg_SetConfigPluggable (TstCfg_PLUGGABLE_UNKNOWN);
+ TstCfg_SetConfigMin (TstCfg_DEFAULT_MIN_QUESTIONS);
+ TstCfg_SetConfigDef (TstCfg_DEFAULT_DEF_QUESTIONS);
+ TstCfg_SetConfigMax (TstCfg_DEFAULT_MAX_QUESTIONS);
+ }
+ else // NumRows == 1
+ {
+ /***** Get minimun, default and maximum *****/
+ row = mysql_fetch_row (mysql_res);
+ TstCfg_GetConfigFromRow (row);
+ }
+
+ /***** Free structure that stores the query result *****/
+ DB_FreeMySQLResult (&mysql_res);
+ }
+
+/*****************************************************************************/
+/************ Get configuration values from a database table row *************/
+/*****************************************************************************/
+
+void TstCfg_GetConfigFromRow (MYSQL_ROW row)
+ {
+ int IntNum;
+ long LongNum;
+ TstCfg_Pluggable_t Pluggable;
+
+ /***** Get whether test are visible via plugins or not *****/
+ TstCfg_SetConfigPluggable (TstCfg_PLUGGABLE_UNKNOWN);
+ for (Pluggable = TstCfg_PLUGGABLE_NO;
+ Pluggable <= TstCfg_PLUGGABLE_YES;
+ Pluggable++)
+ if (!strcmp (row[0],TstCfg_PluggableDB[Pluggable]))
+ {
+ TstCfg_SetConfigPluggable (Pluggable);
+ break;
+ }
+
+ /***** Get number of questions *****/
+ if (sscanf (row[1],"%d",&IntNum) == 1)
+ TstCfg_SetConfigMin ((IntNum < 1) ? 1 :
+ (unsigned) IntNum);
+ else
+ TstCfg_SetConfigMin (TstCfg_DEFAULT_MIN_QUESTIONS);
+
+ if (sscanf (row[2],"%d",&IntNum) == 1)
+ TstCfg_SetConfigDef ((IntNum < 1) ? 1 :
+ (unsigned) IntNum);
+ else
+ TstCfg_SetConfigDef (TstCfg_DEFAULT_DEF_QUESTIONS);
+
+ if (sscanf (row[3],"%d",&IntNum) == 1)
+ TstCfg_SetConfigMax ((IntNum < 1) ? 1 :
+ (unsigned) IntNum);
+ else
+ TstCfg_SetConfigMax (TstCfg_DEFAULT_MAX_QUESTIONS);
+
+ /***** Check and correct numbers *****/
+ TstCfg_CheckAndCorrectMinDefMax ();
+
+ /***** Get minimum time between consecutive tests, per question (row[4]) *****/
+ if (sscanf (row[4],"%ld",&LongNum) == 1)
+ TstCfg_SetConfigMinTimeNxtTstPerQst ((LongNum < 1L) ? 0UL :
+ (unsigned long) LongNum);
+ else
+ TstCfg_SetConfigMinTimeNxtTstPerQst (0UL);
+
+ /***** Get visibility (row[5]) *****/
+ TstCfg_SetConfigVisibility (TsV_GetVisibilityFromStr (row[5]));
+ }
+
+/*****************************************************************************/
+/************* Receive configuration of test for current course **************/
+/*****************************************************************************/
+
+void TstCfg_ReceiveConfigTst (void)
+ {
+ extern const char *Txt_The_test_configuration_has_been_updated;
+
+ /***** Get whether test are visible via plugins or not *****/
+ TstCfg_SetConfigPluggable (TstCfg_GetPluggableFromForm ());
+
+ /***** Get number of questions *****/
+ /* Get minimum number of questions */
+ TstCfg_SetConfigMin ((unsigned)
+ Par_GetParToUnsignedLong ("NumQstMin",
+ 1,
+ UINT_MAX,
+ 1));
+
+ /* Get default number of questions */
+ TstCfg_SetConfigDef ((unsigned)
+ Par_GetParToUnsignedLong ("NumQstDef",
+ 1,
+ UINT_MAX,
+ 1));
+
+ /* Get maximum number of questions */
+ TstCfg_SetConfigMax ((unsigned)
+ Par_GetParToUnsignedLong ("NumQstMax",
+ 1,
+ UINT_MAX,
+ 1));
+
+ /* Check and correct numbers */
+ TstCfg_CheckAndCorrectMinDefMax ();
+
+ /***** Get minimum time between consecutive tests, per question *****/
+ TstCfg_SetConfigMinTimeNxtTstPerQst (Par_GetParToUnsignedLong ("MinTimeNxtTstPerQst",
+ 0,
+ ULONG_MAX,
+ 0));
+
+ /***** Get visibility from form *****/
+ TstCfg_SetConfigVisibility (TsV_GetVisibilityFromForm ());
+
+ /***** Update database *****/
+ DB_QueryREPLACE ("can not save configuration of tests",
+ "REPLACE INTO tst_config"
+ " (CrsCod,Pluggable,Min,Def,Max,MinTimeNxtTstPerQst,Visibility)"
+ " VALUES"
+ " (%ld,'%s',%u,%u,%u,'%lu',%u)",
+ Gbl.Hierarchy.Crs.CrsCod,
+ TstCfg_PluggableDB[TstCfg_GetConfigPluggable ()],
+ TstCfg_GetConfigMin (),
+ TstCfg_GetConfigDef (),
+ TstCfg_GetConfigMax (),
+ TstCfg_GetConfigMinTimeNxtTstPerQst (),
+ TstCfg_GetConfigVisibility ());
+
+ /***** Show confirmation message *****/
+ Ale_ShowAlert (Ale_SUCCESS,Txt_The_test_configuration_has_been_updated);
+
+ /***** Show again the form to configure test *****/
+ Tst_ShowFormConfig ();
+ }
+
+/*****************************************************************************/
+/******************* Get if tests are pluggable from form ********************/
+/*****************************************************************************/
+
+static TstCfg_Pluggable_t TstCfg_GetPluggableFromForm (void)
+ {
+ return (TstCfg_Pluggable_t)
+ Par_GetParToUnsignedLong ("Pluggable",
+ 0,
+ TstCfg_NUM_OPTIONS_PLUGGABLE - 1,
+ (unsigned long) TstCfg_PLUGGABLE_UNKNOWN);
+ }
+
+/*****************************************************************************/
+/**** Check and correct minimum, default and maximum numbers of questions ****/
+/*****************************************************************************/
+
+static void TstCfg_CheckAndCorrectMinDefMax (void)
+ {
+ /***** Check if minimum is correct *****/
+ if (TstCfg_GetConfigMin () < 1)
+ TstCfg_SetConfigMin (1);
+ else if (TstCfg_GetConfigMin () > TstCfg_MAX_QUESTIONS_PER_TEST)
+ TstCfg_SetConfigMin (TstCfg_MAX_QUESTIONS_PER_TEST);
+
+ /***** Check if maximum is correct *****/
+ if (TstCfg_GetConfigMax () < 1)
+ TstCfg_SetConfigMax (1);
+ else if (TstCfg_GetConfigMax () > TstCfg_MAX_QUESTIONS_PER_TEST)
+ TstCfg_SetConfigMax (TstCfg_MAX_QUESTIONS_PER_TEST);
+
+ /***** Check if minimum is lower than maximum *****/
+ if (TstCfg_GetConfigMin () > TstCfg_GetConfigMax ())
+ TstCfg_SetConfigMin (TstCfg_GetConfigMax ());
+
+ /***** Check if default is correct *****/
+ if (TstCfg_GetConfigDef () < TstCfg_GetConfigMin ())
+ TstCfg_SetConfigDef (TstCfg_GetConfigMin ());
+ else if (TstCfg_GetConfigDef () > TstCfg_GetConfigMax ())
+ TstCfg_SetConfigDef (TstCfg_GetConfigMax ());
+ }
+
+/*****************************************************************************/
+/********* Get fields of current test configuration for this course **********/
+/*****************************************************************************/
+
+void TstCfg_SetConfigPluggable (TstCfg_Pluggable_t Pluggable)
+ {
+ TstCfg_Config.Pluggable = Pluggable;
+ }
+
+TstCfg_Pluggable_t TstCfg_GetConfigPluggable (void)
+ {
+ return TstCfg_Config.Pluggable;
+ }
+
+void TstCfg_SetConfigMin (unsigned Min)
+ {
+ TstCfg_Config.Min = Min;
+ }
+
+unsigned TstCfg_GetConfigMin (void)
+ {
+ return TstCfg_Config.Min;
+ }
+
+void TstCfg_SetConfigDef (unsigned Def)
+ {
+ TstCfg_Config.Def = Def;
+ }
+
+unsigned TstCfg_GetConfigDef (void)
+ {
+ return TstCfg_Config.Def;
+ }
+
+void TstCfg_SetConfigMax (unsigned Max)
+ {
+ TstCfg_Config.Max = Max;
+ }
+
+unsigned TstCfg_GetConfigMax (void)
+ {
+ return TstCfg_Config.Max;
+ }
+
+void TstCfg_SetConfigMinTimeNxtTstPerQst (unsigned long MinTimeNxtTstPerQst)
+ {
+ TstCfg_Config.MinTimeNxtTstPerQst = MinTimeNxtTstPerQst;
+ }
+
+unsigned long TstCfg_GetConfigMinTimeNxtTstPerQst (void)
+ {
+ return TstCfg_Config.MinTimeNxtTstPerQst;
+ }
+
+void TstCfg_SetConfigVisibility (unsigned Visibility)
+ {
+ TstCfg_Config.Visibility = Visibility;
+ }
+
+unsigned TstCfg_GetConfigVisibility (void)
+ {
+ return TstCfg_Config.Visibility;
+ }
diff --git a/swad_test_config.h b/swad_test_config.h
new file mode 100644
index 00000000..52e48161
--- /dev/null
+++ b/swad_test_config.h
@@ -0,0 +1,81 @@
+// swad_test_config.h: self-assessment tests configuration
+
+#ifndef _SWAD_TST_CFG
+#define _SWAD_TST_CFG
+/*
+ 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 .
+*/
+/*****************************************************************************/
+/********************************* Headers ***********************************/
+/*****************************************************************************/
+
+#include // To access MySQL databases
+#include // For boolean type
+
+// #include "swad_game.h"
+// #include "swad_media.h"
+// #include "swad_test_result.h"
+
+/*****************************************************************************/
+/***************************** Public constants ******************************/
+/*****************************************************************************/
+
+#define TstCfg_MAX_QUESTIONS_PER_TEST 100 // Absolute maximum number of questions in a test
+
+#define TstCfg_DEFAULT_MIN_QUESTIONS 1
+#define TstCfg_DEFAULT_DEF_QUESTIONS 20 // Number of questions to be generated by default in a self-assessment test
+#define TstCfg_DEFAULT_MAX_QUESTIONS 30 // Maximum number of questions to be generated in a self-assessment test
+
+/*****************************************************************************/
+/******************************* Public types ********************************/
+/*****************************************************************************/
+
+#define TstCfg_NUM_OPTIONS_PLUGGABLE 3
+typedef enum
+ {
+ TstCfg_PLUGGABLE_UNKNOWN = 0,
+ TstCfg_PLUGGABLE_NO = 1,
+ TstCfg_PLUGGABLE_YES = 2,
+ } TstCfg_Pluggable_t;
+
+/*****************************************************************************/
+/***************************** Public prototypes *****************************/
+/*****************************************************************************/
+
+void TstCfg_GetConfigFromDB (void);
+
+void TstCfg_GetConfigFromRow (MYSQL_ROW row);
+void TstCfg_ReceiveConfigTst (void);
+
+void TstCfg_SetConfigPluggable (TstCfg_Pluggable_t Pluggable);
+TstCfg_Pluggable_t TstCfg_GetConfigPluggable (void);
+void TstCfg_SetConfigMin (unsigned Min);
+unsigned TstCfg_GetConfigMin (void);
+void TstCfg_SetConfigDef (unsigned Def);
+unsigned TstCfg_GetConfigDef (void);
+void TstCfg_SetConfigMax (unsigned Max);
+unsigned TstCfg_GetConfigMax (void);
+void TstCfg_SetConfigMinTimeNxtTstPerQst (unsigned long MinTimeNxtTstPerQst);
+unsigned long TstCfg_GetConfigMinTimeNxtTstPerQst (void);
+void TstCfg_SetConfigVisibility (unsigned Visibility);
+unsigned TstCfg_GetConfigVisibility (void);
+
+#endif
diff --git a/swad_test_import.c b/swad_test_import.c
index 027bea4e..e477600a 100644
--- a/swad_test_import.c
+++ b/swad_test_import.c
@@ -81,6 +81,7 @@ static void TsI_GetAnswerFromXML (struct XMLElement *AnswerElem,
static void TsI_WriteHeadingListImportedQst (void);
static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
struct XMLElement *FeedbackElem,
+ const struct Tst_Tags *Tags,
const struct Tst_Question *Question,
bool QuestionExists);
@@ -88,11 +89,12 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
/**************** Put a link (form) to export test questions *****************/
/*****************************************************************************/
-void TsI_PutFormToExportQuestions (void)
+void TsI_PutFormToExportQuestions (const struct Tst_Tags *Tags)
{
extern const char *Txt_Export_questions;
/***** Put a link to create a file with questions *****/
+ Tst_SetParamGblTags (Tags);
Lay_PutContextualLinkIconText (ActLstTstQst,NULL,TsI_PutParamsExportQsts,
"file-import.svg",
Txt_Export_questions);
@@ -536,6 +538,7 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
struct XMLElement *FeedbackElem;
struct XMLElement *AnswerElem;
struct XMLAttribute *Attribute;
+ struct Tst_Tags Tags;
bool AnswerTypeFound;
bool QuestionExists;
struct Tst_Question Question;
@@ -599,22 +602,22 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
if (AnswerTypeFound)
{
/* Get tags */
- for (TagsElem = QuestionElem->FirstChild, Gbl.Test.Tags.Num = 0;
+ for (TagsElem = QuestionElem->FirstChild, Tags.Num = 0;
TagsElem != NULL;
TagsElem = TagsElem->NextBrother)
if (!strcmp (TagsElem->TagName,"tags"))
{
for (TagElem = TagsElem->FirstChild;
- TagElem != NULL && Gbl.Test.Tags.Num < Tst_MAX_TAGS_PER_QUESTION;
+ TagElem != NULL && Tags.Num < Tst_MAX_TAGS_PER_QUESTION;
TagElem = TagElem->NextBrother)
if (!strcmp (TagElem->TagName,"tag"))
{
if (TagElem->Content)
{
- Str_Copy (Gbl.Test.Tags.Txt[Gbl.Test.Tags.Num],
+ Str_Copy (Tags.Txt[Tags.Num],
TagElem->Content,
Tst_MAX_BYTES_TAG);
- Gbl.Test.Tags.Num++;
+ Tags.Num++;
}
}
break; // Only first element "tags"
@@ -685,18 +688,18 @@ static void TsI_ImportQuestionsFromXMLBuffer (const char *XMLBuffer)
TsI_GetAnswerFromXML (AnswerElem,&Question);
/* Make sure that tags, text and answer are not empty */
- if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question))
+ if (Tst_CheckIfQstFormatIsCorrectAndCountNumOptions (&Question,&Tags))
{
/* Check if question already exists in database */
QuestionExists = Tst_CheckIfQuestionExistsInDB (&Question);
/* Write row with this imported question */
TsI_WriteRowImportedQst (StemElem,FeedbackElem,
- &Question,QuestionExists);
+ &Tags,&Question,QuestionExists);
/***** If a new question ==> insert question, tags and answer in the database *****/
if (!QuestionExists)
- if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L,&Question) <= 0)
+ if (Tst_InsertOrUpdateQstTagsAnsIntoDB (-1L,&Question,&Tags) <= 0)
Lay_ShowErrorAndExit ("Can not create question.");
}
}
@@ -917,6 +920,7 @@ static void TsI_WriteHeadingListImportedQst (void)
static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
struct XMLElement *FeedbackElem,
+ const struct Tst_Tags *Tags,
const struct Tst_Question *Question,
bool QuestionExists)
{
@@ -964,12 +968,12 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
/***** Write the question tags *****/
HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd);
- if (Gbl.Test.Tags.Num)
+ if (Tags->Num)
{
/***** Write the tags *****/
HTM_TABLE_Begin (NULL);
for (NumTag = 0;
- NumTag < Gbl.Test.Tags.Num;
+ NumTag < Tags->Num;
NumTag++)
{
HTM_TR_Begin (NULL);
@@ -979,7 +983,7 @@ static void TsI_WriteRowImportedQst (struct XMLElement *StemElem,
HTM_TD_End ();
HTM_TD_Begin ("class=\"%s LT\"",ClassData);
- HTM_Txt (Gbl.Test.Tags.Txt[NumTag]);
+ HTM_Txt (Tags->Txt[NumTag]);
HTM_TD_End ();
HTM_TR_End ();
diff --git a/swad_test_import.h b/swad_test_import.h
index 9703d463..5cd642a4 100644
--- a/swad_test_import.h
+++ b/swad_test_import.h
@@ -39,7 +39,7 @@
/***************************** Public prototypes *****************************/
/*****************************************************************************/
-void TsI_PutFormToExportQuestions (void);
+void TsI_PutFormToExportQuestions (const struct Tst_Tags *Tags);
bool TsI_GetCreateXMLParamFromForm (void);
void TsI_PutFormToImportQuestions (void);
void TsI_CreateXML (unsigned long NumRows,MYSQL_RES *mysql_res);
diff --git a/swad_test_result.c b/swad_test_result.c
index 6d2a3e68..1bddccd0 100644
--- a/swad_test_result.c
+++ b/swad_test_result.c
@@ -158,7 +158,7 @@ void TsR_ShowMyTstResults (void)
TsR_ShowHeaderTestResults ();
/***** List my test results *****/
- Tst_GetConfigTstFromDB (); // To get feedback type
+ TstCfg_GetConfigFromDB (); // To get feedback type
TsR_ShowTstResults (&Gbl.Usrs.Me.UsrDat);
/***** End table and box *****/
@@ -355,7 +355,7 @@ static void TsR_ShowTstResults (struct UsrData *UsrDat)
case Rol_STD:
ICanViewTest = ItsMe;
ICanViewScore = ItsMe &&
- TsV_IsVisibleTotalScore (Gbl.Test.Config.Visibility);
+ TsV_IsVisibleTotalScore (TstCfg_GetConfigVisibility ());
break;
case Rol_NET:
case Rol_TCH:
@@ -514,7 +514,7 @@ static void TsR_ShowTestResultsSummaryRow (bool ItsMe,
{
case Rol_STD:
ICanViewTotalScore = ItsMe &&
- TsV_IsVisibleTotalScore (Gbl.Test.Config.Visibility);
+ TsV_IsVisibleTotalScore (TstCfg_GetConfigVisibility ());
break;
case Rol_NET:
case Rol_TCH:
@@ -613,7 +613,7 @@ void TsR_ShowOneTstResult (void)
/***** Get test result data *****/
TsR_GetTestResultDataByTstCod (TstCod,&TstTimeUTC,
&NumQstsNotBlank,&TotalScore);
- Gbl.Test.Config.Visibility = TsV_MAX_VISIBILITY;
+ TstCfg_SetConfigVisibility (TsV_MAX_VISIBILITY);
/***** Check if I can view this test result *****/
ItsMe = Usr_ItsMe (Gbl.Usrs.Other.UsrDat.UsrCod);
@@ -623,8 +623,8 @@ void TsR_ShowOneTstResult (void)
ICanViewTest = ItsMe;
if (ItsMe)
{
- Tst_GetConfigTstFromDB (); // To get feedback type
- ICanViewScore = TsV_IsVisibleTotalScore (Gbl.Test.Config.Visibility);
+ TstCfg_GetConfigFromDB (); // To get feedback type
+ ICanViewScore = TsV_IsVisibleTotalScore (TstCfg_GetConfigVisibility ());
}
else
ICanViewScore = false;
@@ -781,7 +781,7 @@ void TsR_ShowOneTstResult (void)
/***** Write answers and solutions *****/
TsR_ShowTestResult (&Gbl.Usrs.Other.UsrDat,
Gbl.Test.NumQsts,TstTimeUTC,
- Gbl.Test.Config.Visibility);
+ TstCfg_GetConfigVisibility ());
/***** End table *****/
HTM_TABLE_End ();
diff --git a/swad_text.c b/swad_text.c
index 5eaeec26..a8d14977 100644
--- a/swad_text.c
+++ b/swad_text.c
@@ -51445,11 +51445,11 @@ const char *Txt_TST_HIDDEN_VISIBLE[2] =
#endif
};
-const char *Txt_TST_PLUGGABLE[Tst_NUM_OPTIONS_PLUGGABLE] =
+const char *Txt_TST_PLUGGABLE[TstCfg_NUM_OPTIONS_PLUGGABLE] =
{
- [Tst_PLUGGABLE_UNKNOWN] =
+ [TstCfg_PLUGGABLE_UNKNOWN] =
"",
- [Tst_PLUGGABLE_NO] =
+ [TstCfg_PLUGGABLE_NO] =
#if L==1 // ca
"Tests no visibles des de mòbils (SWADroid, TriSWADos)"
#elif L==2 // de
@@ -51470,7 +51470,7 @@ const char *Txt_TST_PLUGGABLE[Tst_NUM_OPTIONS_PLUGGABLE] =
"Testes não para download de celulares (SWADroid, TriSWADos)"
#endif
,
- [Tst_PLUGGABLE_YES] =
+ [TstCfg_PLUGGABLE_YES] =
#if L==1 // ca
"Tests visibles des de mòbils (SWADroid, TriSWADos), opció recomanada"
#elif L==2 // de