mirror of https://github.com/acanas/swad-core.git
Version19.151
This commit is contained in:
parent
919ab2eeeb
commit
71aa5870b4
3
Makefile
3
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 \
|
||||
|
|
37
swad_API.c
37
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,
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
770
swad_test.c
770
swad_test.c
File diff suppressed because it is too large
Load Diff
89
swad_test.h
89
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);
|
||||
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*****************************************************************************/
|
||||
/*********************************** Headers *********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
// #define _GNU_SOURCE // For asprintf
|
||||
// #include <limits.h> // For UINT_MAX
|
||||
// #include <linux/limits.h> // For PATH_MAX
|
||||
// #include <mysql/mysql.h> // To access MySQL databases
|
||||
// #include <stdbool.h> // For boolean type
|
||||
// #include <stddef.h> // For NULL
|
||||
// #include <stdio.h> // For asprintf
|
||||
// #include <stdlib.h> // For exit, system, malloc, free, etc
|
||||
#include <string.h> // For string functions
|
||||
// #include <sys/stat.h> // For mkdir
|
||||
// #include <sys/types.h> // For mkdir
|
||||
|
||||
// #include "swad_action.h"
|
||||
// #include "swad_box.h"
|
||||
#include "swad_database.h"
|
||||
// #include "swad_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;
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*****************************************************************************/
|
||||
/********************************* Headers ***********************************/
|
||||
/*****************************************************************************/
|
||||
|
||||
#include <mysql/mysql.h> // To access MySQL databases
|
||||
#include <stdbool.h> // 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
|
|
@ -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 ();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue