Version 21.46: Oct 26, 2021 New module swad_test_database for database queries related to self-assessment tests.

This commit is contained in:
acanas 2021-10-26 09:23:06 +02:00
parent 352de7c69d
commit 4120cb75b7
18 changed files with 598 additions and 466 deletions

View File

@ -83,10 +83,11 @@ OBJS = swad_account.o swad_account_database.o swad_action.o swad_admin.o \
swad_statistic_database.o swad_string.o swad_survey.o \
swad_survey_database.o swad_syllabus.o swad_system_config.o \
swad_tab.o swad_tag.o swad_tag_database.o swad_test.o \
swad_test_config.o swad_test_print.o swad_test_visibility.o \
swad_theme.o swad_timeline.o swad_timeline_comment.o \
swad_timeline_database.o swad_timeline_favourite.o swad_timeline_form.o \
swad_timeline_note.o swad_timeline_notification.o swad_timeline_post.o \
swad_test_database.o swad_test_config.o swad_test_print.o \
swad_test_visibility.o swad_theme.o swad_timeline.o \
swad_timeline_comment.o swad_timeline_database.o \
swad_timeline_favourite.o swad_timeline_form.o swad_timeline_note.o \
swad_timeline_notification.o swad_timeline_post.o \
swad_timeline_publication.o swad_timeline_share.o swad_timeline_user.o \
swad_timeline_who.o swad_timetable.o \
swad_user.o \

View File

@ -688,7 +688,7 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] =
[ActReqAssTst ] = {1837,-1,TabUnk,ActReqTst ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_ReceiveTestDraft ,NULL},
[ActAssTst ] = { 98,-1,TabUnk,ActReqTst ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_AssessTest ,NULL},
[ActCfgTst ] = { 451,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Tst_ShowFormConfig ,NULL},
[ActCfgTst ] = { 451,-1,TabUnk,ActReqTst ,0x220,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,TstCfg_CheckAndShowFormConfig ,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 ,TstPrn_SelDatesToSeeMyPrints ,NULL},
@ -4152,7 +4152,7 @@ void Act_AdjustCurrentAction (void)
-------------
If current course has tests and pluggable is unknown,
the only action possible is configure tests *****/
if (Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown ())
if (TstCfg_CheckIfPluggableIsUnknownAndCrsHasTests ())
{
Gbl.Action.Act = ActCfgTst;
Tab_SetCurrentTab ();

View File

@ -602,13 +602,14 @@ TODO: FIX BUG, URGENT! En las fechas como par
TODO: En las encuestas, que los estudiantes no puedan ver los resultados hasta que no finalice el plazo.
*/
#define Log_PLATFORM_VERSION "SWAD 21.45.1 (2021-10-25)"
#define Log_PLATFORM_VERSION "SWAD 21.46 (2021-10-26)"
#define CSS_FILE "swad20.45.css"
#define JS_FILE "swad20.69.1.js"
/*
TODO: Rename CENTRE to CENTER in help wiki.
TODO: Rename ASSESSMENT.Announcements to ASSESSMENT.Calls_for_exams
Version 21.46: Oct 26, 2021 New module swad_test_database for database queries related to self-assessment tests. (321036 lines)
Version 21.45.1: Oct 25, 2021 Code refactoring in test questions. (320932 lines)
Version 21.45: Oct 25, 2021 Functions moved to module swad_question. (320930 lines)
Version 21.44: Oct 25, 2021 Functions moved to module swad_question. (320928 lines)

View File

@ -1928,7 +1928,7 @@ void Exa_DB_RemoveAllPrintsFromCrs (long CrsCod)
}
/*****************************************************************************/
/************* Store user's answers of an test exam into database ************/
/*************** Store user's answers of a test into database ****************/
/*****************************************************************************/
void Exa_DB_StoreOneQstOfPrint (const struct ExaPrn_Print *Print,

View File

@ -230,7 +230,7 @@ void ExaPrn_ShowExamPrint (void)
ExaLog_SetIfCanAnswer (true);
}
/***** Show test exam to be answered *****/
/***** Show test to be answered *****/
ExaPrn_ShowExamPrintToFillIt (&Exams,&Exam,&Print);
}
else // Session not open or accessible
@ -1111,7 +1111,7 @@ static void ExaPrn_ComputeScoreAndStoreQuestionOfPrint (struct ExaPrn_Print *Pri
}
}
/***** Store test exam question in database *****/
/***** Store test question in database *****/
Exa_DB_StoreOneQstOfPrint (Print,
QstInd); // 0, 1, 2, 3...
}

View File

@ -1755,7 +1755,7 @@ static void ExaRes_ShowExamResultGrade (const struct Exa_Exam *Exam,
}
/*****************************************************************************/
/************** Show user's and correct answers of a test exam ***************/
/**************** Show user's and correct answers of a test ******************/
/*****************************************************************************/
static void ExaRes_ShowExamAnswers (struct UsrData *UsrDat,

View File

@ -26,42 +26,19 @@
/*****************************************************************************/
#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_error.h"
#include "swad_exam_set.h"
#include "swad_figure.h"
#include "swad_form.h"
#include "swad_global.h"
// #include "swad_hierarchy_level.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_question.h"
#include "swad_question_import.h"
#include "swad_tag_database.h"
#include "swad_test.h"
// #include "swad_test_config.h"
// #include "swad_test_print.h"
// #include "swad_test_visibility.h"
// #include "swad_theme.h"
// #include "swad_user.h"
// #include "swad_xml.h"
/*****************************************************************************/
/***************************** Public constants ******************************/

View File

@ -36,10 +36,6 @@
#include "swad_media.h"
#include "swad_string.h"
#include "swad_tag.h"
// #include "swad_test.h"
// #include "swad_test_config.h"
// #include "swad_test_visibility.h"
// #include "swad_user.h"
/*****************************************************************************/
/***************************** Public constants ******************************/

View File

@ -25,19 +25,10 @@
/*********************************** Headers *********************************/
/*****************************************************************************/
// #include <mysql/mysql.h> // To access MySQL databases
// #include <stdbool.h> // For boolean type
// #include <stdlib.h> // For free
// #include <string.h> // For string functions
// #include "swad_action.h"
#include "swad_database.h"
// #include "swad_error.h"
// #include "swad_form.h"
#include "swad_global.h"
#include "swad_tag.h"
#include "swad_tag_database.h"
// #include "swad_theme.h"
/*****************************************************************************/
/***************************** Public constants ******************************/

View File

@ -57,6 +57,7 @@
#include "swad_tag_database.h"
#include "swad_test.h"
#include "swad_test_config.h"
#include "swad_test_database.h"
#include "swad_test_print.h"
#include "swad_test_visibility.h"
#include "swad_theme.h"
@ -94,17 +95,6 @@ static void Tst_ShowFormRequestTest (struct Qst_Questions *Questions);
static void TstPrn_GetAnswersFromForm (struct TstPrn_Print *Print);
static bool Tst_CheckIfNextTstAllowed (void);
static unsigned Tst_GetNumTstExamsGeneratedByMe (void);
static void Tst_DB_IncreaseMyNumTstExams (void);
static void Tst_DB_UpdateLastAccTst (unsigned NumQsts);
static void Tst_PutIconsTests (__attribute__((unused)) void *Args);
static void Tst_ShowFormConfigTst (void);
static void Tst_PutInputFieldNumQst (const char *Field,const char *Label,
unsigned Value);
static void Tst_GetQuestionsForNewTestFromDB (struct Qst_Questions *Questions,
struct TstPrn_Print *Print);
@ -223,7 +213,7 @@ void Tst_ShowNewTest (void)
extern const char *Txt_No_questions_found_matching_your_search_criteria;
struct Qst_Questions Questions;
struct TstPrn_Print Print;
unsigned NumTstExamsGeneratedByMe;
unsigned NumPrintsGeneratedByMe;
/***** Create test *****/
Qst_Constructor (&Questions);
@ -242,16 +232,16 @@ void Tst_ShowNewTest (void)
if (Print.NumQsts.All)
{
/***** Increase number of exams generated (answered or not) by me *****/
Tst_DB_IncreaseMyNumTstExams ();
NumTstExamsGeneratedByMe = Tst_GetNumTstExamsGeneratedByMe ();
Tst_DB_IncreaseNumMyPrints ();
NumPrintsGeneratedByMe = TstPrn_GetNumPrintsGeneratedByMe ();
/***** Create new test exam in database *****/
/***** Create new test print in database *****/
TstPrn_CreatePrintInDB (&Print);
TstPrn_ComputeScoresAndStoreQuestionsOfPrint (&Print,
false); // Don't update question score
/***** Show test exam to be answered *****/
TstPrn_ShowTestPrintToFillIt (&Print,NumTstExamsGeneratedByMe,TstPrn_REQUEST);
/***** Show test print to be answered *****/
TstPrn_ShowTestPrintToFillIt (&Print,NumPrintsGeneratedByMe,TstPrn_REQUEST);
/***** Update date-time of my next allowed access to test *****/
if (Gbl.Usrs.Me.Role.Logged == Rol_STD)
@ -272,7 +262,7 @@ void Tst_ShowNewTest (void)
}
/*****************************************************************************/
/** Receive the draft of a test exam already (total or partially) answered ***/
/** Receive the draft of a test print already (total or partially) answered **/
/*****************************************************************************/
void Tst_ReceiveTestDraft (void)
@ -286,7 +276,7 @@ void Tst_ReceiveTestDraft (void)
TstCfg_GetConfigFromDB ();
/***** Get basic parameters of the exam *****/
/* Get test exam code from form */
/* Get test print code from form */
TstPrn_ResetPrint (&Print);
if ((Print.PrnCod = TstPrn_GetParamPrnCod ()) <= 0)
Err_WrongTestExit ();
@ -294,7 +284,7 @@ void Tst_ReceiveTestDraft (void)
/* Get number of this test from form */
NumTst = Tst_GetParamNumTst ();
/***** Get test exam print from database *****/
/***** Get test print from database *****/
TstPrn_GetPrintDataByPrnCod (&Print);
/****** Get test status in database for this session-course-num.test *****/
@ -303,13 +293,13 @@ void Tst_ReceiveTestDraft (void)
NumTst);
else // Print not yet sent
{
/***** Get test exam print questions from database *****/
/***** Get test print questions from database *****/
TstPrn_GetPrintQuestionsFromDB (&Print);
/***** Get answers from form to assess a test *****/
TstPrn_GetAnswersFromForm (&Print);
/***** Update test exam in database *****/
/***** Update test print in database *****/
TstPrn_ComputeScoresAndStoreQuestionsOfPrint (&Print,
false); // Don't update question score
TstPrn_UpdatePrintInDB (&Print);
@ -318,7 +308,7 @@ void Tst_ReceiveTestDraft (void)
/* Begin alert */
Ale_ShowAlert (Ale_WARNING,Txt_Please_review_your_answers_before_submitting_the_exam);
/* Show the same test exam to be answered */
/* Show the same test print to be answered */
TstPrn_ShowTestPrintToFillIt (&Print,NumTst,TstPrn_CONFIRM);
}
}
@ -342,7 +332,7 @@ void Tst_AssessTest (void)
TstCfg_GetConfigFromDB ();
/***** Get basic parameters of the exam *****/
/* Get test exam code from form */
/* Get test print code from form */
TstPrn_ResetPrint (&Print);
if ((Print.PrnCod = TstPrn_GetParamPrnCod ()) <= 0)
Err_WrongTestExit ();
@ -350,7 +340,7 @@ void Tst_AssessTest (void)
/* Get number of this test from form */
NumTst = Tst_GetParamNumTst ();
/***** Get test exam from database *****/
/***** Get test print from database *****/
TstPrn_GetPrintDataByPrnCod (&Print);
/****** Get test status in database for this session-course-num.test *****/
@ -359,17 +349,17 @@ void Tst_AssessTest (void)
NumTst);
else // Print not yet sent
{
/***** Get test exam questions from database *****/
/***** Get test print questions from database *****/
TstPrn_GetPrintQuestionsFromDB (&Print);
/***** Get answers from form to assess a test *****/
TstPrn_GetAnswersFromForm (&Print);
/***** Get if test exam will be visible by teachers *****/
/***** Get if test print will be visible by teachers *****/
Print.Sent = true; // The exam has been finished and sent by student
Print.AllowTeachers = Par_GetParToBool ("AllowTchs");
/***** Update test exam in database *****/
/***** Update test print in database *****/
TstPrn_ComputeScoresAndStoreQuestionsOfPrint (&Print,
Gbl.Usrs.Me.Role.Logged == Rol_STD); // Update question score?
TstPrn_UpdatePrintInDB (&Print);
@ -412,7 +402,7 @@ void Tst_AssessTest (void)
}
/*****************************************************************************/
/****** Get questions and answers from form to assess a test exam print ******/
/******** Get questions and answers from form to assess a test print *********/
/*****************************************************************************/
static void TstPrn_GetAnswersFromForm (struct TstPrn_Print *Print)
@ -453,19 +443,9 @@ static bool Tst_CheckIfNextTstAllowed (void)
return true;
/***** Get date of next allowed access to test from database *****/
if (DB_QuerySELECT (&mysql_res,"can not get last access to test",
"SELECT UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)-"
"UNIX_TIMESTAMP()," // row[0]
"UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)" // row[1]
" FROM crs_user_settings"
" WHERE UsrCod=%ld"
" AND CrsCod=%ld",
TstCfg_GetConfigMinTimeNxtTstPerQst (),
TstCfg_GetConfigMinTimeNxtTstPerQst (),
Gbl.Usrs.Me.UsrDat.UsrCod,
Gbl.Hierarchy.Crs.CrsCod) == 1)
if (Tst_DB_GetDateNextTstAllowed (&mysql_res))
{
/* Get seconds from now to next access to test */
/* Get seconds from now to next access to test (row[0]) */
row = mysql_fetch_row (mysql_res);
if (row[0])
if (sscanf (row[0],"%ld",&NumSecondsFromNowToNextAccTst) == 1)
@ -473,7 +453,7 @@ static bool Tst_CheckIfNextTstAllowed (void)
TimeNextTestUTC = Dat_GetUNIXTimeFromStr (row[1]);
}
else
Err_ShowErrorAndExit ("Error when reading date of next allowed access to test.");
Err_WrongDateExit ();
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
@ -482,107 +462,26 @@ static bool Tst_CheckIfNextTstAllowed (void)
if (NumSecondsFromNowToNextAccTst > 0)
{
/***** Write warning *****/
Ale_ShowAlert (Ale_WARNING,"%s:<br /><span id=\"date_next_test\"></span>."
"<script type=\"text/javascript\">"
"writeLocalDateHMSFromUTC('date_next_test',%ld,"
"%u,',&nbsp;',%u,true,true,true,0x7);"
"</script>",
Ale_ShowAlert (Ale_WARNING,"%s:<br />"
"<span id=\"date_next_test\"></span>."
"<script type=\"text/javascript\">"
"writeLocalDateHMSFromUTC('date_next_test',%ld,"
"%u,',&nbsp;',%u,true,true,true,0x7);"
"</script>",
Txt_You_can_not_take_a_new_test_until,
(long) TimeNextTestUTC,
(unsigned) Gbl.Prefs.DateFormat,
(unsigned) Gbl.Prefs.Language);
return false;
}
return true;
}
/*****************************************************************************/
/***************** Get number of test exams generated by me ******************/
/*****************************************************************************/
static unsigned Tst_GetNumTstExamsGeneratedByMe (void)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned long NumRows;
unsigned NumTstExamsGeneratedByMe = 0;
if (Gbl.Usrs.Me.IBelongToCurrentCrs)
{
/***** Get number of test exams generated by me from database *****/
NumRows = DB_QuerySELECT (&mysql_res,"can not get number of test exams generated",
"SELECT NumAccTst" // row[0]
" FROM crs_user_settings"
" WHERE UsrCod=%ld"
" AND CrsCod=%ld",
Gbl.Usrs.Me.UsrDat.UsrCod,
Gbl.Hierarchy.Crs.CrsCod);
if (NumRows == 0)
NumTstExamsGeneratedByMe = 0;
else if (NumRows == 1)
{
/* Get number of hits */
row = mysql_fetch_row (mysql_res);
if (row[0] == NULL)
NumTstExamsGeneratedByMe = 0;
else if (sscanf (row[0],"%u",&NumTstExamsGeneratedByMe) != 1)
NumTstExamsGeneratedByMe = 0;
}
else
Err_ShowErrorAndExit ("Error when getting number of hits to test.");
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
return NumTstExamsGeneratedByMe;
}
/*****************************************************************************/
/*********** Update my number of accesses to test in this course *************/
/*****************************************************************************/
static void Tst_DB_IncreaseMyNumTstExams (void)
{
/***** Trivial check *****/
if (!Gbl.Usrs.Me.IBelongToCurrentCrs)
return;
/***** Update my number of accesses to test in this course *****/
DB_QueryUPDATE ("can not update the number of accesses to test",
"UPDATE crs_user_settings"
" SET NumAccTst=NumAccTst+1"
" WHERE UsrCod=%ld"
" AND CrsCod=%ld",
Gbl.Usrs.Me.UsrDat.UsrCod,
Gbl.Hierarchy.Crs.CrsCod);
}
/*****************************************************************************/
/************ Update date-time of my next allowed access to test *************/
/*****************************************************************************/
static void Tst_DB_UpdateLastAccTst (unsigned NumQsts)
{
/***** Update date-time and number of questions of this test *****/
DB_QueryUPDATE ("can not update time and number of questions of this test",
"UPDATE crs_user_settings"
" SET LastAccTst=NOW(),"
"NumQstsLastTst=%u"
" WHERE UsrCod=%ld"
" AND CrsCod=%ld",
NumQsts,
Gbl.Usrs.Me.UsrDat.UsrCod,
Gbl.Hierarchy.Crs.CrsCod);
}
/*****************************************************************************/
/********************* Put contextual icons in tests *************************/
/*****************************************************************************/
static void Tst_PutIconsTests (__attribute__((unused)) void *Args)
void Tst_PutIconsTests (__attribute__((unused)) void *Args)
{
switch (Gbl.Usrs.Me.Role.Logged)
{
@ -613,228 +512,6 @@ static void Tst_PutIconsTests (__attribute__((unused)) void *Args)
Fig_PutIconToShowFigure (Fig_TESTS);
}
/*****************************************************************************/
/***************************** Form to rename tags ***************************/
/*****************************************************************************/
void Tst_ShowFormConfig (void)
{
extern const char *Txt_Please_specify_if_you_allow_downloading_the_question_bank_from_other_applications;
/***** If current course has tests and pluggable is unknown... *****/
if (Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown ())
Ale_ShowAlert (Ale_WARNING,Txt_Please_specify_if_you_allow_downloading_the_question_bank_from_other_applications);
/***** Form to configure test *****/
Tst_ShowFormConfigTst ();
}
/*****************************************************************************/
/*************** 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 NumRows;
TstCfg_Pluggable_t Pluggable;
/***** Get pluggability of tests for current course from database *****/
NumRows = (unsigned)
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 Tag_DB_CheckIfCurrentCrsHasTestTags (); // Return true if course has tests
return false; // Pluggable is not unknown
}
/*****************************************************************************/
/********************* Show a form to to configure test **********************/
/*****************************************************************************/
static void Tst_ShowFormConfigTst (void)
{
extern const char *Hlp_ASSESSMENT_Tests_configuring_tests;
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[TstCfg_NUM_OPTIONS_PLUGGABLE];
extern const char *Txt_Number_of_questions;
extern const char *Txt_minimum;
extern const char *Txt_default;
extern const char *Txt_maximum;
extern const char *Txt_Minimum_time_seconds_per_question_between_two_tests;
extern const char *Txt_Result_visibility;
extern const char *Txt_Save_changes;
struct Qst_Questions Questions;
TstCfg_Pluggable_t Pluggable;
char StrMinTimeNxtTstPerQst[Cns_MAX_DECIMAL_DIGITS_ULONG + 1];
/***** Create test *****/
Qst_Constructor (&Questions);
/***** Read test configuration from database *****/
TstCfg_GetConfigFromDB ();
/***** Begin box *****/
Box_BoxBegin (NULL,Txt_Configure_tests,
Tst_PutIconsTests,NULL,
Hlp_ASSESSMENT_Tests_configuring_tests,Box_NOT_CLOSABLE);
/***** Begin form *****/
Frm_BeginForm (ActRcvCfgTst);
/***** Tests are visible from plugins? *****/
HTM_TABLE_BeginCenterPadding (2);
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"%s RT\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
HTM_TxtColon (Txt_Plugins);
HTM_TD_End ();
HTM_TD_Begin ("class=\"LB\"");
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 == TstCfg_GetConfigPluggable () ? " checked=\"checked\"" :
"");
HTM_Txt (Txt_TST_PLUGGABLE[Pluggable]);
HTM_LABEL_End ();
HTM_BR ();
}
HTM_TD_End ();
HTM_TR_End ();
/***** Number of questions *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"%s RT\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
HTM_TxtColon (Txt_Number_of_questions);
HTM_TD_End ();
HTM_TD_Begin ("class=\"LB\"");
HTM_TABLE_BeginPadding (2);
Tst_PutInputFieldNumQst ("NumQstMin",Txt_minimum,
TstCfg_GetConfigMin ()); // Minimum number of questions
Tst_PutInputFieldNumQst ("NumQstDef",Txt_default,
TstCfg_GetConfigDef ()); // Default number of questions
Tst_PutInputFieldNumQst ("NumQstMax",Txt_maximum,
TstCfg_GetConfigMax ()); // Maximum number of questions
HTM_TABLE_End ();
HTM_TD_End ();
HTM_TR_End ();
/***** Minimum time between consecutive tests, per question *****/
HTM_TR_Begin (NULL);
/* Label */
Frm_LabelColumn ("RT","MinTimeNxtTstPerQst",
Txt_Minimum_time_seconds_per_question_between_two_tests);
/* Data */
HTM_TD_Begin ("class=\"LB\"");
snprintf (StrMinTimeNxtTstPerQst,sizeof (StrMinTimeNxtTstPerQst),"%lu",
TstCfg_GetConfigMinTimeNxtTstPerQst ());
HTM_INPUT_TEXT ("MinTimeNxtTstPerQst",Cns_MAX_DECIMAL_DIGITS_ULONG,StrMinTimeNxtTstPerQst,
HTM_DONT_SUBMIT_ON_CHANGE,
"id=\"MinTimeNxtTstPerQst\" size=\"7\" required=\"required\"");
HTM_TD_End ();
HTM_TR_End ();
/***** Visibility of test exams *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"%s RT\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
HTM_TxtColon (Txt_Result_visibility);
HTM_TD_End ();
HTM_TD_Begin ("class=\"LB\"");
TstVis_PutVisibilityCheckboxes (TstCfg_GetConfigVisibility ());
HTM_TD_End ();
HTM_TR_End ();
HTM_TABLE_End ();
/***** Send button *****/
Btn_PutConfirmButton (Txt_Save_changes);
/***** End form *****/
Frm_EndForm ();
/***** End box *****/
Box_BoxEnd ();
/***** Destroy test *****/
Qst_Destructor (&Questions);
}
/*****************************************************************************/
/*************** Get configuration of test for current course ****************/
/*****************************************************************************/
static void Tst_PutInputFieldNumQst (const char *Field,const char *Label,
unsigned Value)
{
char StrValue[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"RM\"");
HTM_LABEL_Begin ("for=\"%s\" class=\"DAT\"",Field);
HTM_Txt (Label);
HTM_LABEL_End ();
HTM_TD_End ();
HTM_TD_Begin ("class=\"LM\"");
snprintf (StrValue,sizeof (StrValue),"%u",Value);
HTM_INPUT_TEXT (Field,Cns_MAX_DECIMAL_DIGITS_UINT,StrValue,
HTM_DONT_SUBMIT_ON_CHANGE,
"id=\"%s\" size=\"3\" required=\"required\"",Field);
HTM_TD_End ();
HTM_TR_End ();
}
/*****************************************************************************/
/************** Get questions for a new test from the database ***************/
/*****************************************************************************/
@ -1001,7 +678,7 @@ static void Tst_GetQuestionsForNewTestFromDB (struct Qst_Questions *Questions,
Print->PrintedQuestions[QstInd].StrAnswers[0] = '\0';
}
/***** Get if test exam will be visible by teachers *****/
/***** Get if test print will be visible by teachers *****/
Print->AllowTeachers = Par_GetParToBool ("AllowTchs");
}
@ -1170,7 +847,7 @@ bool Tst_GetParamsTst (struct Qst_Questions *Questions,
}
/*****************************************************************************/
/******** Get parameter with the number of test exam generated by me *********/
/******** Get parameter with the number of test prints generated by me *******/
/*****************************************************************************/
static unsigned Tst_GetParamNumTst (void)
@ -1264,7 +941,7 @@ unsigned Tst_CountNumQuestionsInList (const char *ListQuestions)
void Tst_RemoveCrsTests (long CrsCod)
{
/***** Remove all test exam prints made in the course *****/
/***** Remove all test prints made in the course *****/
TstPrn_RemoveCrsPrints (CrsCod);
/***** Remove test configuration of the course *****/

View File

@ -64,11 +64,10 @@ void Tst_ShowNewTest (void);
void Tst_ReceiveTestDraft (void);
void Tst_AssessTest (void);
void Tst_PutIconsTests (__attribute__((unused)) void *Args);
bool Tst_GetParamsTst (struct Qst_Questions *Questions,
Tst_ActionToDoWithQuestions_t ActionToDoWithQuestions);
void Tst_ShowFormConfig (void);
bool Tst_CheckIfCourseHaveTestsAndPluggableIsUnknown (void);
unsigned Tst_CountNumQuestionsInList (const char *ListQuestions);

View File

@ -28,7 +28,9 @@
#include <string.h> // For string functions
#include "swad_database.h"
#include "swad_form.h"
#include "swad_global.h"
#include "swad_tag_database.h"
#include "swad_test.h"
#include "swad_test_config.h"
#include "swad_test_visibility.h"
@ -78,9 +80,235 @@ struct TstCfg_Config TstCfg_Config;
/***************************** Private prototypes ****************************/
/*****************************************************************************/
static void TstCfg_ShowFormConfig (void);
static void TstCfg_PutInputFieldNumQsts (const char *Field,const char *Label,
unsigned Value);
static TstCfg_Pluggable_t TstCfg_GetPluggableFromForm (void);
static void TstCfg_CheckAndCorrectMinDefMax (void);
/*****************************************************************************/
/***************************** Form to rename tags ***************************/
/*****************************************************************************/
void TstCfg_CheckAndShowFormConfig (void)
{
extern const char *Txt_Please_specify_if_you_allow_downloading_the_question_bank_from_other_applications;
/***** If current course has tests and pluggable is unknown... *****/
if (TstCfg_CheckIfPluggableIsUnknownAndCrsHasTests ())
Ale_ShowAlert (Ale_WARNING,Txt_Please_specify_if_you_allow_downloading_the_question_bank_from_other_applications);
/***** Form to configure test *****/
TstCfg_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 TstCfg_CheckIfPluggableIsUnknownAndCrsHasTests (void)
{
extern const char *TstCfg_PluggableDB[TstCfg_NUM_OPTIONS_PLUGGABLE];
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRows;
TstCfg_Pluggable_t Pluggable;
/***** Get pluggability of tests for current course from database *****/
NumRows = (unsigned)
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 Tag_DB_CheckIfCurrentCrsHasTestTags (); // Return true if course has test tags
return false; // Pluggable is not unknown
}
/*****************************************************************************/
/********************* Show a form to to configure test **********************/
/*****************************************************************************/
static void TstCfg_ShowFormConfig (void)
{
extern const char *Hlp_ASSESSMENT_Tests_configuring_tests;
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[TstCfg_NUM_OPTIONS_PLUGGABLE];
extern const char *Txt_Number_of_questions;
extern const char *Txt_minimum;
extern const char *Txt_default;
extern const char *Txt_maximum;
extern const char *Txt_Minimum_time_seconds_per_question_between_two_tests;
extern const char *Txt_Result_visibility;
extern const char *Txt_Save_changes;
struct Qst_Questions Questions;
TstCfg_Pluggable_t Pluggable;
char StrMinTimeNxtTstPerQst[Cns_MAX_DECIMAL_DIGITS_ULONG + 1];
/***** Create test *****/
Qst_Constructor (&Questions);
/***** Read test configuration from database *****/
TstCfg_GetConfigFromDB ();
/***** Begin box *****/
Box_BoxBegin (NULL,Txt_Configure_tests,
Tst_PutIconsTests,NULL,
Hlp_ASSESSMENT_Tests_configuring_tests,Box_NOT_CLOSABLE);
/***** Begin form *****/
Frm_BeginForm (ActRcvCfgTst);
/***** Tests are visible from plugins? *****/
HTM_TABLE_BeginCenterPadding (2);
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"%s RT\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
HTM_TxtColon (Txt_Plugins);
HTM_TD_End ();
HTM_TD_Begin ("class=\"LB\"");
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 == TstCfg_GetConfigPluggable () ? " checked=\"checked\"" :
"");
HTM_Txt (Txt_TST_PLUGGABLE[Pluggable]);
HTM_LABEL_End ();
HTM_BR ();
}
HTM_TD_End ();
HTM_TR_End ();
/***** Number of questions *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"%s RT\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
HTM_TxtColon (Txt_Number_of_questions);
HTM_TD_End ();
HTM_TD_Begin ("class=\"LB\"");
HTM_TABLE_BeginPadding (2);
TstCfg_PutInputFieldNumQsts ("NumQstMin",Txt_minimum,
TstCfg_GetConfigMin ()); // Minimum number of questions
TstCfg_PutInputFieldNumQsts ("NumQstDef",Txt_default,
TstCfg_GetConfigDef ()); // Default number of questions
TstCfg_PutInputFieldNumQsts ("NumQstMax",Txt_maximum,
TstCfg_GetConfigMax ()); // Maximum number of questions
HTM_TABLE_End ();
HTM_TD_End ();
HTM_TR_End ();
/***** Minimum time between consecutive tests, per question *****/
HTM_TR_Begin (NULL);
/* Label */
Frm_LabelColumn ("RT","MinTimeNxtTstPerQst",
Txt_Minimum_time_seconds_per_question_between_two_tests);
/* Data */
HTM_TD_Begin ("class=\"LB\"");
snprintf (StrMinTimeNxtTstPerQst,sizeof (StrMinTimeNxtTstPerQst),"%lu",
TstCfg_GetConfigMinTimeNxtTstPerQst ());
HTM_INPUT_TEXT ("MinTimeNxtTstPerQst",Cns_MAX_DECIMAL_DIGITS_ULONG,StrMinTimeNxtTstPerQst,
HTM_DONT_SUBMIT_ON_CHANGE,
"id=\"MinTimeNxtTstPerQst\" size=\"7\" required=\"required\"");
HTM_TD_End ();
HTM_TR_End ();
/***** Visibility of test prints *****/
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"%s RT\"",The_ClassFormInBox[Gbl.Prefs.Theme]);
HTM_TxtColon (Txt_Result_visibility);
HTM_TD_End ();
HTM_TD_Begin ("class=\"LB\"");
TstVis_PutVisibilityCheckboxes (TstCfg_GetConfigVisibility ());
HTM_TD_End ();
HTM_TR_End ();
HTM_TABLE_End ();
/***** Send button *****/
Btn_PutConfirmButton (Txt_Save_changes);
/***** End form *****/
Frm_EndForm ();
/***** End box *****/
Box_BoxEnd ();
/***** Destroy test *****/
Qst_Destructor (&Questions);
}
/*****************************************************************************/
/*************** Get configuration of test for current course ****************/
/*****************************************************************************/
static void TstCfg_PutInputFieldNumQsts (const char *Field,const char *Label,
unsigned Value)
{
char StrValue[Cns_MAX_DECIMAL_DIGITS_UINT + 1];
HTM_TR_Begin (NULL);
HTM_TD_Begin ("class=\"RM\"");
HTM_LABEL_Begin ("for=\"%s\" class=\"DAT\"",Field);
HTM_Txt (Label);
HTM_LABEL_End ();
HTM_TD_End ();
HTM_TD_Begin ("class=\"LM\"");
snprintf (StrValue,sizeof (StrValue),"%u",Value);
HTM_INPUT_TEXT (Field,Cns_MAX_DECIMAL_DIGITS_UINT,StrValue,
HTM_DONT_SUBMIT_ON_CHANGE,
"id=\"%s\" size=\"3\" required=\"required\"",Field);
HTM_TD_End ();
HTM_TR_End ();
}
/*****************************************************************************/
/*************** Get configuration of test for current course ****************/
/*****************************************************************************/
@ -242,7 +470,7 @@ void TstCfg_ReceiveConfigTst (void)
Ale_ShowAlert (Ale_SUCCESS,Txt_The_test_configuration_has_been_updated);
/***** Show again the form to configure test *****/
Tst_ShowFormConfig ();
TstCfg_CheckAndShowFormConfig ();
}
/*****************************************************************************/

View File

@ -56,6 +56,9 @@ typedef enum
/***************************** Public prototypes *****************************/
/*****************************************************************************/
void TstCfg_CheckAndShowFormConfig (void);
bool TstCfg_CheckIfPluggableIsUnknownAndCrsHasTests (void);
void TstCfg_GetConfigFromDB (void);
void TstCfg_GetConfigFromRow (MYSQL_ROW row);

163
swad_test_database.c Normal file
View File

@ -0,0 +1,163 @@
// swad_test_database.c: self-assessment tests, operations with database
/*
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-2021 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_error.h"
// #include "swad_exam_set.h"
// #include "swad_figure.h"
// #include "swad_form.h"
#include "swad_global.h"
// #include "swad_hierarchy_level.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_question.h"
// #include "swad_question_import.h"
// #include "swad_tag_database.h"
// #include "swad_test.h"
#include "swad_test_config.h"
// #include "swad_test_print.h"
// #include "swad_test_visibility.h"
// #include "swad_theme.h"
// #include "swad_user.h"
// #include "swad_xml.h"
/*****************************************************************************/
/***************************** Public constants ******************************/
/*****************************************************************************/
/*****************************************************************************/
/**************************** Private constants ******************************/
/*****************************************************************************/
/*****************************************************************************/
/******************************* Private types *******************************/
/*****************************************************************************/
/*****************************************************************************/
/************** External global variables from others modules ****************/
/*****************************************************************************/
extern struct Globals Gbl;
/*****************************************************************************/
/************************* Private global variables **************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Private prototypes ****************************/
/*****************************************************************************/
/*****************************************************************************/
/************** Update my number of test prints in this course ***************/
/*****************************************************************************/
void Tst_DB_IncreaseNumMyPrints (void)
{
/***** Trivial check *****/
if (!Gbl.Usrs.Me.IBelongToCurrentCrs)
return;
/***** Update my number of accesses to test in this course *****/
DB_QueryUPDATE ("can not update the number of accesses to test",
"UPDATE crs_user_settings"
" SET NumAccTst=NumAccTst+1"
" WHERE UsrCod=%ld"
" AND CrsCod=%ld",
Gbl.Usrs.Me.UsrDat.UsrCod,
Gbl.Hierarchy.Crs.CrsCod);
}
/*****************************************************************************/
/******** Update date-time and number of questions of this test print ********/
/*****************************************************************************/
void Tst_DB_UpdateLastAccTst (unsigned NumQsts)
{
DB_QueryUPDATE ("can not update time and number of questions of this test",
"UPDATE crs_user_settings"
" SET LastAccTst=NOW(),"
"NumQstsLastTst=%u"
" WHERE UsrCod=%ld"
" AND CrsCod=%ld",
NumQsts,
Gbl.Usrs.Me.UsrDat.UsrCod,
Gbl.Hierarchy.Crs.CrsCod);
}
/*****************************************************************************/
/********** Get date of next allowed access to test from database ************/
/*****************************************************************************/
unsigned Tst_DB_GetDateNextTstAllowed (MYSQL_RES **mysql_res)
{
return (unsigned)
DB_QuerySELECT (mysql_res,"can not get date of last test print",
"SELECT UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)-"
"UNIX_TIMESTAMP()," // row[0]
"UNIX_TIMESTAMP(LastAccTst+INTERVAL (NumQstsLastTst*%lu) SECOND)" // row[1]
" FROM crs_user_settings"
" WHERE UsrCod=%ld"
" AND CrsCod=%ld",
TstCfg_GetConfigMinTimeNxtTstPerQst (),
TstCfg_GetConfigMinTimeNxtTstPerQst (),
Gbl.Usrs.Me.UsrDat.UsrCod,
Gbl.Hierarchy.Crs.CrsCod);
}
/*****************************************************************************/
/**************** Get number of test prints generated by me ******************/
/*****************************************************************************/
unsigned Tst_DB_GetNumPrintsGeneratedByMe (MYSQL_RES **mysql_res)
{
return (unsigned)
DB_QuerySELECT (mysql_res,"can not get number of test prints generated",
"SELECT NumAccTst" // row[0]
" FROM crs_user_settings"
" WHERE UsrCod=%ld"
" AND CrsCod=%ld",
Gbl.Usrs.Me.UsrDat.UsrCod,
Gbl.Hierarchy.Crs.CrsCod);
}

57
swad_test_database.h Normal file
View File

@ -0,0 +1,57 @@
// swad_test_database.h: self-assessment tests, operations with database
#ifndef _SWAD_TST_DB
#define _SWAD_TST_DB
/*
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-2021 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 "swad_exam.h"
// #include "swad_game.h"
// #include "swad_media.h"
// #include "swad_question.h"
// #include "swad_question_type.h"
// #include "swad_test_config.h"
// #include "swad_test_print.h"
/*****************************************************************************/
/***************************** Public constants ******************************/
/*****************************************************************************/
/*****************************************************************************/
/******************************* Public types ********************************/
/*****************************************************************************/
/*****************************************************************************/
/***************************** Public prototypes *****************************/
/*****************************************************************************/
void Tst_DB_IncreaseNumMyPrints (void);
void Tst_DB_UpdateLastAccTst (unsigned NumQsts);
unsigned Tst_DB_GetDateNextTstAllowed (MYSQL_RES **mysql_res);
unsigned Tst_DB_GetNumPrintsGeneratedByMe (MYSQL_RES **mysql_res);
#endif

View File

@ -1,4 +1,4 @@
// swad_test_print.c: test exam prints made by users
// swad_test_print.c: test prints made by users
/*
SWAD (Shared Workspace At a Distance),
@ -42,6 +42,7 @@
#include "swad_photo.h"
#include "swad_question.h"
#include "swad_test.h"
#include "swad_test_database.h"
#include "swad_test_print.h"
#include "swad_test_visibility.h"
#include "swad_user.h"
@ -210,14 +211,14 @@ static void TstPrn_ResetPrintExceptPrnCod (struct TstPrn_Print *Print)
}
/*****************************************************************************/
/************** Create new blank test exam print in database *****************/
/**************** Create new blank test print in database ********************/
/*****************************************************************************/
void TstPrn_CreatePrintInDB (struct TstPrn_Print *Print)
{
/***** Insert new test exam print into table *****/
/***** Insert new test print into table *****/
Print->PrnCod =
DB_QueryINSERTandReturnCode ("can not create new test exam print",
DB_QueryINSERTandReturnCode ("can not create new test print",
"INSERT INTO tst_exams"
" (CrsCod,UsrCod,StartTime,EndTime,"
"NumQsts,NumQstsNotBlank,"
@ -232,14 +233,14 @@ void TstPrn_CreatePrintInDB (struct TstPrn_Print *Print)
}
/*****************************************************************************/
/******************** Update test exam print in database *********************/
/*********************** Update test print in database ***********************/
/*****************************************************************************/
void TstPrn_UpdatePrintInDB (const struct TstPrn_Print *Print)
{
/***** Update test exam print in database *****/
/***** Update test print in database *****/
Str_SetDecimalPointToUS (); // To print the floating point as a dot
DB_QueryUPDATE ("can not update test exam",
DB_QueryUPDATE ("can not update test",
"UPDATE tst_exams"
" SET EndTime=NOW(),"
"NumQstsNotBlank=%u,"
@ -262,11 +263,11 @@ void TstPrn_UpdatePrintInDB (const struct TstPrn_Print *Print)
}
/*****************************************************************************/
/****************** Show a test exam print to be answered ********************/
/********************* Show a test print to be answered **********************/
/*****************************************************************************/
void TstPrn_ShowTestPrintToFillIt (struct TstPrn_Print *Print,
unsigned NumTstExamsGeneratedByMe,
unsigned NumPrintsGeneratedByMe,
TstPrn_RequestOrConfirm_t RequestOrConfirm)
{
extern const char *Hlp_ASSESSMENT_Tests;
@ -295,7 +296,7 @@ void TstPrn_ShowTestPrintToFillIt (struct TstPrn_Print *Print,
/***** Begin form *****/
Frm_BeginForm (Action[RequestOrConfirm]);
TstPrn_PutParamPrnCod (Print->PrnCod);
Par_PutHiddenParamUnsigned (NULL,"NumTst",NumTstExamsGeneratedByMe);
Par_PutHiddenParamUnsigned (NULL,"NumTst",NumPrintsGeneratedByMe);
/***** Begin table *****/
HTM_TABLE_BeginWideMarginPadding (10);
@ -333,7 +334,7 @@ void TstPrn_ShowTestPrintToFillIt (struct TstPrn_Print *Print,
Btn_PutConfirmButton (Txt_Continue);
break;
case TstPrn_CONFIRM:
/* Will the test exam be visible by teachers? */
/* Will the test be visible by teachers? */
TstPrn_PutCheckBoxAllowTeachers (true);
/* Send button */
@ -569,7 +570,7 @@ static void TstPrn_WriteTxtAnsToFill (const struct TstPrn_PrintedQuestion *Print
}
/*****************************************************************************/
/************* Put checkbox to allow teachers to see test exam ***************/
/**************** Put checkbox to allow teachers to see test *****************/
/*****************************************************************************/
static void TstPrn_PutCheckBoxAllowTeachers (bool AllowTeachers)
@ -590,7 +591,7 @@ static void TstPrn_PutCheckBoxAllowTeachers (bool AllowTeachers)
}
/*****************************************************************************/
/********************* Show test exam after assessing it *********************/
/************************ Show test after assessing it ***********************/
/*****************************************************************************/
void TstPrn_ShowPrintAfterAssess (struct TstPrn_Print *Print)
@ -626,7 +627,7 @@ void TstPrn_ShowPrintAfterAssess (struct TstPrn_Print *Print)
&Question,QuestionExists,
TstCfg_GetConfigVisibility ());
/***** Store test exam question in database *****/
/***** Store test question in database *****/
TstPrn_StoreOneQstOfPrintInDB (Print,QstInd);
/***** Compute total score *****/
@ -787,7 +788,7 @@ void TstPrn_ComputeScoresAndStoreQuestionsOfPrint (struct TstPrn_Print *Print,
TstPrn_ComputeAnswerScore (&Print->PrintedQuestions[QstInd],&Question);
Qst_QstDestructor (&Question);
/* Store test exam question in database */
/* Store test question in database */
TstPrn_StoreOneQstOfPrintInDB (Print,
QstInd); // 0, 1, 2, 3...
@ -1865,7 +1866,7 @@ static void TstPrn_StoreOneQstOfPrintInDB (const struct TstPrn_Print *Print,
{
/***** Insert question and user's answers into database *****/
Str_SetDecimalPointToUS (); // To print the floating point as a dot
DB_QueryREPLACE ("can not update a question of a test exam",
DB_QueryREPLACE ("can not update a question of a test",
"REPLACE INTO tst_exam_questions"
" (ExaCod,QstCod,QstInd,Score,Indexes,Answers)"
" VALUES"
@ -1880,7 +1881,7 @@ static void TstPrn_StoreOneQstOfPrintInDB (const struct TstPrn_Print *Print,
}
/*****************************************************************************/
/************* Select users and dates to show their test exams ***************/
/*************** Select users and dates to show their tests ******************/
/*****************************************************************************/
void TstPrn_SelUsrsToViewUsrsPrints (void)
@ -1904,7 +1905,7 @@ static void TstPrn_PutFormToSelectUsrsToViewUsrsPrints (__attribute__((unused))
}
/*****************************************************************************/
/******************** Select dates to show my test exams *********************/
/*********************** Select dates to show my tests ***********************/
/*****************************************************************************/
void TstPrn_SelDatesToSeeMyPrints (void)
@ -1935,7 +1936,7 @@ void TstPrn_SelDatesToSeeMyPrints (void)
}
/*****************************************************************************/
/***************************** Show my test exams ****************************/
/******************************* Show my tests *******************************/
/*****************************************************************************/
void TstPrn_ShowMyPrints (void)
@ -1954,7 +1955,7 @@ void TstPrn_ShowMyPrints (void)
/***** Header of the table with the list of users *****/
TstPrn_ShowHeaderPrints (Usr_ME);
/***** List my test exams *****/
/***** List my tests *****/
TstCfg_GetConfigFromDB (); // To get visibility
TstPrn_ShowUsrPrints (&Gbl.Usrs.Me.UsrDat);
@ -1963,7 +1964,7 @@ void TstPrn_ShowMyPrints (void)
}
/*****************************************************************************/
/******************** Get users and show their test exams ********************/
/********************** Get users and show their test ************************/
/*****************************************************************************/
void TstPrn_GetUsrsAndShowPrints (void)
@ -1994,7 +1995,7 @@ static void TstPrn_ShowUsrsPrints (__attribute__((unused)) void *Args)
/***** Header of the table with the list of users *****/
TstPrn_ShowHeaderPrints (Usr_OTHER);
/***** List the test exams of the selected users *****/
/***** List the tests of the selected users *****/
Ptr = Gbl.Usrs.Selected.List[Rol_UNK];
while (*Ptr)
{
@ -2006,7 +2007,7 @@ static void TstPrn_ShowUsrsPrints (__attribute__((unused)) void *Args)
Usr_DONT_GET_ROLE_IN_CURRENT_CRS))
if (Usr_CheckIfICanViewTstExaMchResult (&Gbl.Usrs.Other.UsrDat))
{
/***** Show test exams *****/
/***** Show tests *****/
Gbl.Usrs.Other.UsrDat.Accepted = Usr_CheckIfUsrHasAcceptedInCurrentCrs (&Gbl.Usrs.Other.UsrDat);
TstPrn_ShowUsrPrints (&Gbl.Usrs.Other.UsrDat);
}
@ -2017,7 +2018,7 @@ static void TstPrn_ShowUsrsPrints (__attribute__((unused)) void *Args)
}
/*****************************************************************************/
/************************ Show header of my test exams ***********************/
/************************** Show header of my tests **************************/
/*****************************************************************************/
static void TstPrn_ShowHeaderPrints (Usr_MeOrOther_t MeOrOther)
@ -2104,7 +2105,7 @@ static void TstPrn_ShowUsrPrints (struct UsrData *UsrDat)
Start | End Start | End
*/
NumPrints = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get test exams of a user",
DB_QuerySELECT (&mysql_res,"can not get tests of a user",
"SELECT ExaCod" // row[0]
" FROM tst_exams"
" WHERE CrsCod=%ld"
@ -2121,7 +2122,7 @@ static void TstPrn_ShowUsrPrints (struct UsrData *UsrDat)
HTM_TR_Begin (NULL);
Usr_ShowTableCellWithUsrData (UsrDat,NumPrints);
/***** Get and print test exams *****/
/***** Get and print tests *****/
if (NumPrints)
{
for (NumPrint = 0;
@ -2235,7 +2236,7 @@ static void TstPrn_ShowUsrPrints (struct UsrData *UsrDat)
Ico_PutIconNotVisible ();
HTM_TD_End ();
/* Link to show this test exam */
/* Link to show this test */
HTM_TD_Begin ("class=\"RT LINE_LEFT COLOR%u\"",Gbl.RowEvenOdd);
if (ICanView.Result)
{
@ -2294,7 +2295,7 @@ static void TstPrn_ShowUsrPrints (struct UsrData *UsrDat)
}
/*****************************************************************************/
/*************** Write parameter with code of test exam print ****************/
/***************** Write parameter with code of test print ******************/
/*****************************************************************************/
void TstPrn_PutParamPrnCod (long ExaCod)
@ -2303,17 +2304,17 @@ void TstPrn_PutParamPrnCod (long ExaCod)
}
/*****************************************************************************/
/*************** Get parameter with code of test exam print ******************/
/***************** Get parameter with code of test print *********************/
/*****************************************************************************/
long TstPrn_GetParamPrnCod (void)
{
/***** Get code of test exam print *****/
/***** Get code of test print *****/
return Par_GetParToLong ("PrnCod");
}
/*****************************************************************************/
/**************** Show row with summary of user's test exams *****************/
/****************** Show row with summary of user's tess *********************/
/*****************************************************************************/
static void TstPrn_ShowPrintsSummaryRow (bool ItsMe,
@ -2405,7 +2406,7 @@ static void TstPrn_ShowPrintsSummaryRow (bool ItsMe,
}
/*****************************************************************************/
/******************** Show one test exam of another user *********************/
/*********************** Show one test of another user ***********************/
/*****************************************************************************/
void TstPrn_ShowOnePrint (void)
@ -2429,7 +2430,7 @@ void TstPrn_ShowOnePrint (void)
if ((Print.PrnCod = TstPrn_GetParamPrnCod ()) <= 0)
Err_WrongTestExit ();
/***** Get test exam data *****/
/***** Get test data *****/
TstPrn_GetPrintDataByPrnCod (&Print);
/***** Get if I can see print result and score *****/
@ -2439,7 +2440,7 @@ void TstPrn_ShowOnePrint (void)
if (ICanView.Result) // I am allowed to view this test print result
{
/***** Get questions and user's answers of the test exam from database *****/
/***** Get questions and user's answers of the test from database *****/
TstPrn_GetPrintQuestionsFromDB (&Print);
/***** Begin box *****/
@ -2600,7 +2601,7 @@ void TstPrn_ShowOnePrint (void)
/***** End box *****/
Box_BoxEnd ();
}
else // I am not allowed to view this test exam
else // I am not allowed to view this test
Err_NoPermissionExit ();
}
@ -2649,7 +2650,7 @@ static void TstRes_CheckIfICanSeePrintResult (const struct TstPrn_Print *Print,
}
/*****************************************************************************/
/********************* Show test tags in this test exam **********************/
/************************ Show test tags in this test ************************/
/*****************************************************************************/
static void TstPrn_ShowTagsPresentInAPrint (long ResCod)
@ -2659,8 +2660,7 @@ static void TstPrn_ShowTagsPresentInAPrint (long ResCod)
/***** Get all tags of questions in this test *****/
NumTags = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get tags"
" present in a test exam",
DB_QuerySELECT (&mysql_res,"can not get tags present in a test",
"SELECT tst_tags.TagTxt" // row[0]
" FROM (SELECT DISTINCT(tst_question_tags.TagCod)"
" FROM tst_question_tags,"
@ -2678,7 +2678,7 @@ static void TstPrn_ShowTagsPresentInAPrint (long ResCod)
}
/*****************************************************************************/
/************** Show user's and correct answers of a test exam ***************/
/**************** Show user's and correct answers of a test ******************/
/*****************************************************************************/
void TstPrn_ShowPrintAnswers (struct UsrData *UsrDat,
@ -2717,7 +2717,7 @@ void TstPrn_ShowPrintAnswers (struct UsrData *UsrDat,
}
/*****************************************************************************/
/************ Get data of a test exam using its test exam code ***************/
/**************** Get data of a test using its test code *********************/
/*****************************************************************************/
void TstPrn_GetPrintDataByPrnCod (struct TstPrn_Print *Print)
@ -2726,7 +2726,7 @@ void TstPrn_GetPrintDataByPrnCod (struct TstPrn_Print *Print)
MYSQL_ROW row;
/***** Make database query *****/
if (DB_QuerySELECT (&mysql_res,"can not get data of a test exam",
if (DB_QuerySELECT (&mysql_res,"can not get data of a test",
"SELECT UsrCod," // row[0]
"UNIX_TIMESTAMP(StartTime)," // row[1]
"UNIX_TIMESTAMP(EndTime)," // row[2]
@ -2761,7 +2761,7 @@ void TstPrn_GetPrintDataByPrnCod (struct TstPrn_Print *Print)
/* Get if exam has been sent (row[5]) */
Print->Sent = (row[5][0] == 'Y');
/* Get if teachers are allowed to see this test exam (row[6]) */
/* Get if teachers are allowed to see this test (row[6]) */
Print->AllowTeachers = (row[6][0] == 'Y');
/* Get score (row[7]) */
@ -2778,7 +2778,7 @@ void TstPrn_GetPrintDataByPrnCod (struct TstPrn_Print *Print)
}
/*****************************************************************************/
/*********** Get the questions of a test exam print from database ************/
/************* Get the questions of a test print from database ***************/
/*****************************************************************************/
void TstPrn_GetPrintQuestionsFromDB (struct TstPrn_Print *Print)
@ -2788,9 +2788,9 @@ void TstPrn_GetPrintQuestionsFromDB (struct TstPrn_Print *Print)
unsigned NumQsts;
unsigned QstInd;
/***** Get questions of a test exam print from database *****/
/***** Get questions of a test print from database *****/
NumQsts = (unsigned)
DB_QuerySELECT (&mysql_res,"can not get questions of a test exam",
DB_QuerySELECT (&mysql_res,"can not get questions of a test",
"SELECT QstCod," // row[0]
"Score," // row[1]
"Indexes," // row[2]
@ -2835,13 +2835,13 @@ void TstPrn_GetPrintQuestionsFromDB (struct TstPrn_Print *Print)
}
/*****************************************************************************/
/******************* Remove test exam prints made by a user ******************/
/********************** Remove test prints made by a user ********************/
/*****************************************************************************/
void TstPrn_RemovePrintsMadeByUsrInAllCrss (long UsrCod)
{
/***** Remove test prints questions for the given user *****/
DB_QueryDELETE ("can not remove test exams made by a user",
DB_QueryDELETE ("can not remove tests made by a user",
"DELETE FROM tst_exam_questions"
" USING tst_exams,"
"tst_exam_questions"
@ -2850,20 +2850,20 @@ void TstPrn_RemovePrintsMadeByUsrInAllCrss (long UsrCod)
UsrCod);
/***** Remove test prints made by the given user *****/
DB_QueryDELETE ("can not remove test exams made by a user",
DB_QueryDELETE ("can not remove tests made by a user",
"DELETE FROM tst_exams"
" WHERE UsrCod=%ld",
UsrCod);
}
/*****************************************************************************/
/************ Remove test exam prints made by a user in a course *************/
/************** Remove test prints made by a user in a course ****************/
/*****************************************************************************/
void TstPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod)
{
/***** Remove test exams made by the given user *****/
DB_QueryDELETE ("can not remove test exams made by a user in a course",
/***** Remove tests made by the given user *****/
DB_QueryDELETE ("can not remove tests made by a user in a course",
"DELETE FROM tst_exam_questions"
" USING tst_exams,"
"tst_exam_questions"
@ -2873,7 +2873,7 @@ void TstPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod)
CrsCod,
UsrCod);
DB_QueryDELETE ("can not remove test exams made by a user in a course",
DB_QueryDELETE ("can not remove tests made by a user in a course",
"DELETE FROM tst_exams"
" WHERE CrsCod=%ld"
" AND UsrCod=%ld",
@ -2882,13 +2882,13 @@ void TstPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod)
}
/*****************************************************************************/
/**************** Remove all test exam prints made in a course ***************/
/****************** Remove all test prints made in a course ******************/
/*****************************************************************************/
void TstPrn_RemoveCrsPrints (long CrsCod)
{
/***** Remove questions of test exams made in the course *****/
DB_QueryDELETE ("can not remove test exams made in a course",
/***** Remove questions of tests made in the course *****/
DB_QueryDELETE ("can not remove tests made in a course",
"DELETE FROM tst_exam_questions"
" USING tst_exams,"
"tst_exam_questions"
@ -2896,9 +2896,46 @@ void TstPrn_RemoveCrsPrints (long CrsCod)
" AND tst_exams.ExaCod=tst_exam_questions.ExaCod",
CrsCod);
/***** Remove test exams made in the course *****/
DB_QueryDELETE ("can not remove test exams made in a course",
/***** Remove tests made in the course *****/
DB_QueryDELETE ("can not remove tests made in a course",
"DELETE FROM tst_exams"
" WHERE CrsCod=%ld",
CrsCod);
}
/*****************************************************************************/
/***************** Get number of test prints generated by me *****************/
/*****************************************************************************/
unsigned TstPrn_GetNumPrintsGeneratedByMe (void)
{
MYSQL_RES *mysql_res;
MYSQL_ROW row;
unsigned NumRows;
unsigned NumPrintsGeneratedByMe = 0;
if (Gbl.Usrs.Me.IBelongToCurrentCrs)
{
/***** Get number of test prints generated by me from database *****/
NumRows = Tst_DB_GetNumPrintsGeneratedByMe (&mysql_res);
if (NumRows == 0)
NumPrintsGeneratedByMe = 0;
else if (NumRows == 1)
{
/* Get number of hits */
row = mysql_fetch_row (mysql_res);
if (row[0] == NULL)
NumPrintsGeneratedByMe = 0;
else if (sscanf (row[0],"%u",&NumPrintsGeneratedByMe) != 1)
NumPrintsGeneratedByMe = 0;
}
else
Err_ShowErrorAndExit ("Error when getting number of tests.");
/***** Free structure that stores the query result *****/
DB_FreeMySQLResult (&mysql_res);
}
return NumPrintsGeneratedByMe;
}

View File

@ -1,4 +1,4 @@
// swad_test_print.h: test exam prints made by users
// swad_test_print.h: test prints made by users
#ifndef _SWAD_TST_PRN
#define _SWAD_TST_PRN
@ -95,7 +95,7 @@ void TstPrn_CreatePrintInDB (struct TstPrn_Print *Print);
void TstPrn_UpdatePrintInDB (const struct TstPrn_Print *Print);
void TstPrn_ShowTestPrintToFillIt (struct TstPrn_Print *Print,
unsigned NumTstExamsGeneratedByMe,
unsigned NumPrintsGeneratedByMe,
TstPrn_RequestOrConfirm_t RequestOrConfirm);
void TstPrn_ShowPrintAfterAssess (struct TstPrn_Print *Print);
@ -160,4 +160,6 @@ void TstPrn_RemovePrintsMadeByUsrInAllCrss (long UsrCod);
void TstPrn_RemovePrintsMadeByUsrInCrs (long UsrCod,long CrsCod);
void TstPrn_RemoveCrsPrints (long CrsCod);
unsigned TstPrn_GetNumPrintsGeneratedByMe (void);
#endif

View File

@ -1,4 +1,4 @@
// swad_test_visibility.c: visibility of test exams
// swad_test_visibility.c: visibility of test prints
/*
SWAD (Shared Workspace At a Distance),