diff --git a/Makefile b/Makefile index b2dbd6aa..bbfa517d 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/swad_action.c b/swad_action.c index dbfefa2d..22acf136 100644 --- a/swad_action.c +++ b/swad_action.c @@ -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 (); diff --git a/swad_changelog.h b/swad_changelog.h index 702c0ec8..b82edc93 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -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) diff --git a/swad_exam_database.c b/swad_exam_database.c index ae38db60..d50b8436 100644 --- a/swad_exam_database.c +++ b/swad_exam_database.c @@ -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, diff --git a/swad_exam_print.c b/swad_exam_print.c index 5df6f823..e541e769 100644 --- a/swad_exam_print.c +++ b/swad_exam_print.c @@ -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... } diff --git a/swad_exam_result.c b/swad_exam_result.c index 30c987ad..49ec2af4 100644 --- a/swad_exam_result.c +++ b/swad_exam_result.c @@ -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, diff --git a/swad_question.c b/swad_question.c index f7bcc133..4ca05416 100644 --- a/swad_question.c +++ b/swad_question.c @@ -26,42 +26,19 @@ /*****************************************************************************/ #define _GNU_SOURCE // For asprintf -// #include // For UINT_MAX -// #include // For PATH_MAX -// #include // To access MySQL databases -// #include // For boolean type -// #include // For NULL #include // For asprintf -// #include // For exit, system, malloc, free, etc #include // For string functions -// #include // For mkdir -// #include // For mkdir -// #include "swad_action.h" -// #include "swad_box.h" #include "swad_database.h" #include "swad_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 ******************************/ diff --git a/swad_question.h b/swad_question.h index 47b764d3..1c2fc68c 100644 --- a/swad_question.h +++ b/swad_question.h @@ -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 ******************************/ diff --git a/swad_tag_database.c b/swad_tag_database.c index ae8b24f9..11c5fb7d 100644 --- a/swad_tag_database.c +++ b/swad_tag_database.c @@ -25,19 +25,10 @@ /*********************************** Headers *********************************/ /*****************************************************************************/ -// #include // To access MySQL databases -// #include // For boolean type -// #include // For free -// #include // 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 ******************************/ diff --git a/swad_test.c b/swad_test.c index 4cfa5902..e3b93422 100644 --- a/swad_test.c +++ b/swad_test.c @@ -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:
." - "", + Ale_ShowAlert (Ale_WARNING,"%s:
" + "." + "", 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 *****/ diff --git a/swad_test.h b/swad_test.h index 5eceb86b..90f4bf56 100644 --- a/swad_test.h +++ b/swad_test.h @@ -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); diff --git a/swad_test_config.c b/swad_test_config.c index b236f678..5a915d13 100644 --- a/swad_test_config.c +++ b/swad_test_config.c @@ -28,7 +28,9 @@ #include // 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 (); } /*****************************************************************************/ diff --git a/swad_test_config.h b/swad_test_config.h index 0106475e..2df2e2f0 100644 --- a/swad_test_config.h +++ b/swad_test_config.h @@ -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); diff --git a/swad_test_database.c b/swad_test_database.c new file mode 100644 index 00000000..1dde6cac --- /dev/null +++ b/swad_test_database.c @@ -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 . +*/ +/*****************************************************************************/ +/*********************************** Headers *********************************/ +/*****************************************************************************/ + +// #define _GNU_SOURCE // For asprintf +// #include // For UINT_MAX +// #include // For PATH_MAX +// #include // To access MySQL databases +// #include // For boolean type +// #include // For NULL +// #include // For asprintf +// #include // For exit, system, malloc, free, etc +// #include // For string functions +// #include // For mkdir +// #include // For mkdir + +// #include "swad_action.h" +// #include "swad_box.h" +#include "swad_database.h" +// #include "swad_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); + } diff --git a/swad_test_database.h b/swad_test_database.h new file mode 100644 index 00000000..fef73822 --- /dev/null +++ b/swad_test_database.h @@ -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 . +*/ +/*****************************************************************************/ +/********************************* Headers ***********************************/ +/*****************************************************************************/ + +#include // 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 diff --git a/swad_test_print.c b/swad_test_print.c index 755dd01e..ddc701b9 100644 --- a/swad_test_print.c +++ b/swad_test_print.c @@ -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; + } diff --git a/swad_test_print.h b/swad_test_print.h index eac6796d..2e93e32b 100644 --- a/swad_test_print.h +++ b/swad_test_print.h @@ -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 diff --git a/swad_test_visibility.c b/swad_test_visibility.c index 1eb4e291..d708c838 100644 --- a/swad_test_visibility.c +++ b/swad_test_visibility.c @@ -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),