diff --git a/Makefile b/Makefile index de6eb94f..fd9f9cf6 100644 --- a/Makefile +++ b/Makefile @@ -36,7 +36,7 @@ OBJS = swad_account.o swad_action.o swad_agenda.o swad_alert.o \ swad_database.o swad_date.o swad_degree.o swad_degree_config.o \ swad_degree_type.o swad_department.o swad_duplicate.o \ swad_enrolment.o swad_exam.o swad_exam_announcement.o \ - swad_exam_event.o swad_exam_result.o \ + swad_exam_event.o swad_exam_result.o swad_exam_set.o \ swad_figure.o swad_figure_cache.o swad_file.o swad_file_browser.o \ swad_file_extension.o swad_file_MIME.o swad_firewall.o swad_follow.o \ swad_form.o swad_forum.o \ diff --git a/swad_action.c b/swad_action.c index 9fd63b30..d3ce9f21 100644 --- a/swad_action.c +++ b/swad_action.c @@ -50,6 +50,7 @@ #include "swad_exam_announcement.h" #include "swad_exam_event.h" #include "swad_exam_result.h" +#include "swad_exam_set.h" #include "swad_enrolment.h" #include "swad_figure.h" #include "swad_follow.h" diff --git a/swad_changelog.h b/swad_changelog.h index 4cfa6e9e..167b2200 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -548,10 +548,11 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - * En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 19.214.1 (2020-05-07)" +#define Log_PLATFORM_VERSION "SWAD 19.215 (2020-05-07)" #define CSS_FILE "swad19.193.1.css" #define JS_FILE "swad19.193.1.js" /* + Version 19.215: May 07, 2020 New module exam_set for set of questions. (301695 lines) Version 19.214.1: May 07, 2020 Change color of dates on current exam event. (301597 lines) Version 19.214: May 06, 2020 New API function getLocations. (301568 lines) 1 change necessary in database: diff --git a/swad_exam.c b/swad_exam.c index 7410a327..6f9c6730 100644 --- a/swad_exam.c +++ b/swad_exam.c @@ -38,6 +38,7 @@ #include "swad_exam.h" #include "swad_exam_event.h" #include "swad_exam_result.h" +#include "swad_exam_set.h" #include "swad_exam_type.h" #include "swad_figure.h" #include "swad_form.h" @@ -65,9 +66,6 @@ extern struct Globals Gbl; #define Exa_MAX_ANSWERS_PER_QUESTION 10 -#define ExaSet_MAX_SELECTED_QUESTIONS 10000 -#define ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS (ExaSet_MAX_SELECTED_QUESTIONS * (Cns_MAX_DECIMAL_DIGITS_LONG + 1)) - /* Score range [0...max.score] will be converted to grade range [0...max.grade] @@ -113,7 +111,6 @@ extern struct Globals Gbl; /*****************************************************************************/ static void Exa_ListAllExams (struct Exa_Exams *Exams); -static bool Exa_CheckIfICanEditExams (void); static void Exa_PutIconsListExams (void *Exams); static void Exa_PutIconToCreateNewExam (struct Exa_Exams *Exams); static void Exa_PutButtonToCreateNewExam (struct Exa_Exams *Exams); @@ -131,93 +128,20 @@ static void Exa_PutIconsToRemEditOneExam (struct Exa_Exams *Exams, const struct Exa_Exam *Exam, const char *Anchor); -static void ExaSet_PutParamsOneQst (void *Exams); static void Exa_PutHiddenParamOrder (Exa_Order_t SelectedOrder); static Exa_Order_t Exa_GetParamOrder (void); -static unsigned ExaSet_GetNumQstsInSet (long SetCod); - -static void Exa_GetExamTxtFromDB (long ExaCod,char Txt[Cns_MAX_BYTES_TEXT + 1]); - static void Exa_RemoveExamFromAllTables (long ExaCod); -static bool ExaSet_CheckIfSimilarSetExists (const struct ExaSet_Set *Set, - const char Title[ExaSet_MAX_BYTES_TITLE + 1]); static bool Exa_CheckIfSimilarExamExists (const struct Exa_Exam *Exam); -static void Exa_PutFormsOneExam (struct Exa_Exams *Exams, - struct Exa_Exam *Exam, - struct ExaSet_Set *Set, - bool ItsANewExam); - -static void ExaSet_PutFormNewSet (struct Exa_Exams *Exams, - struct Exa_Exam *Exam, - struct ExaSet_Set *Set, - unsigned MaxSetInd); -static void ExaSet_ReceiveSetFieldsFromForm (struct ExaSet_Set *Set); -static bool ExaSet_CheckSetTitleReceivedFromForm (const struct ExaSet_Set *Set, - const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]); - -static void Exa_PutFormEditionExam (struct Exa_Exams *Exams, - struct Exa_Exam *Exam, - char Txt[Cns_MAX_BYTES_TEXT + 1], - bool ItsANewExam); static void Exa_ReceiveExamFieldsFromForm (struct Exa_Exam *Exam, char Txt[Cns_MAX_BYTES_TEXT + 1]); static bool Exa_CheckExamFieldsReceivedFromForm (const struct Exa_Exam *Exam); -static void ExaSet_CreateSet (struct ExaSet_Set *Set); -static void ExaSet_UpdateSet (const struct ExaSet_Set *Set); -static void ExaSet_UpdateSetTitleDB (const struct ExaSet_Set *Set, - const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]); -static void ExaSet_UpdateNumQstsToExamDB (const struct ExaSet_Set *Set, - unsigned NumQstsToExam); - static void Exa_CreateExam (struct Exa_Exam *Exam,const char *Txt); static void Exa_UpdateExam (struct Exa_Exam *Exam,const char *Txt); -static void ExaSet_PutParamSetCod (long SetCod); - -static unsigned ExaSet_GetSetIndFromSetCod (long ExaCod,long SetCod); -static long ExaSet_GetSetCodFromSetInd (long ExaCod,unsigned SetInd); - -static unsigned ExaSet_GetMaxSetIndexInExam (long ExaCod); - -static unsigned ExaSet_GetPrevSetIndexInExam (long ExaCod,unsigned SetInd); -static unsigned ExaSet_GetNextSetIndexInExam (long ExaCod,unsigned SetInd); - -static void ExaSet_ListExamSets (struct Exa_Exams *Exams, - struct Exa_Exam *Exam, - struct ExaSet_Set *Set); -static void ExaSet_ListSetQuestions (struct Exa_Exams *Exams, - const struct Exa_Exam *Exam, - const struct ExaSet_Set *Set); -static void ExaSet_ListOneOrMoreSetsForEdition (struct Exa_Exams *Exams, - const struct Exa_Exam *Exam, - unsigned MaxSetInd, - unsigned NumSets, - MYSQL_RES *mysql_res, - bool ICanEditSets); -static void ExaSet_PutTableHeadingForSets (void); - -static void ExaSet_ResetSet (struct ExaSet_Set *Set); -// static void Exa_PutParamSetCod (void *SetCod); -static void ExaSet_ListOneOrMoreQuestionsForEdition (struct Exa_Exams *Exams, - unsigned NumQsts, - MYSQL_RES *mysql_res, - bool ICanEditQuestions); - -static void Exa_PutIconToAddNewQuestions (void *Exams); -static void Exa_PutButtonToAddNewQuestions (struct Exa_Exams *Exams); - -static void ExaSet_AllocateListSelectedQuestions (struct Exa_Exams *Exams); -static void ExaSet_FreeListsSelectedQuestions (struct Exa_Exams *Exams); - -static void ExaSet_ExchangeSets (long ExaCod, - unsigned SetIndTop,unsigned SetIndBottom); - -static bool Exa_CheckIfEditable (const struct Exa_Exam *Exam); - /*****************************************************************************/ /******************************* Reset exams *********************************/ /*****************************************************************************/ @@ -392,7 +316,7 @@ static void Exa_ListAllExams (struct Exa_Exams *Exams) /************************ Check if I can edit exams **************************/ /*****************************************************************************/ -static bool Exa_CheckIfICanEditExams (void) +bool Exa_CheckIfICanEditExams (void) { switch (Gbl.Usrs.Me.Role.Logged) { @@ -784,29 +708,6 @@ static void Exa_PutIconsToRemEditOneExam (struct Exa_Exams *Exams, Exa_PutParams,Exams); } -/*****************************************************************************/ -/************ Put parameter to move/remove one set of questions **************/ -/*****************************************************************************/ - -void ExaSet_PutParamsOneSet (void *Exams) - { - if (Exams) - { - Exa_PutParams (Exams); - ExaSet_PutParamSetCod (((struct Exa_Exams *) Exams)->SetCod); - } - } - -/*****************************************************************************/ -/**************** Put parameter to move/remove one question ******************/ -/*****************************************************************************/ - -static void ExaSet_PutParamsOneQst (void *Exams) - { - ExaSet_PutParamsOneSet (Exams); - Tst_PutParamQstCod (&(((struct Exa_Exams *) Exams)->QstCod)); - } - /*****************************************************************************/ /*********************** Params used to edit an exam **************************/ /*****************************************************************************/ @@ -845,16 +746,6 @@ long Exa_GetParamExamCod (void) return Par_GetParToLong ("ExaCod"); } -/*****************************************************************************/ -/********************** Get parameter with code of set ***********************/ -/*****************************************************************************/ - -long ExaSet_GetParamSetCod (void) - { - /***** Get code of set *****/ - return Par_GetParToLong ("SetCod"); - } - /*****************************************************************************/ /******************* Get parameters used to edit an exam **********************/ /*****************************************************************************/ @@ -1043,81 +934,6 @@ void Exa_GetListSelectedExaCods (struct Exa_Exams *Exams) } } -/*****************************************************************************/ -/********************* Get number of questions in a set **********************/ -/*****************************************************************************/ - -static unsigned ExaSet_GetNumQstsInSet (long SetCod) - { - /***** Get number of questions in set from database *****/ - return - (unsigned) DB_QueryCOUNT ("can not get number of questions in a set", - "SELECT COUNT(*) FROM exa_questions" - " WHERE SetCod=%ld", - SetCod); - } - -/*****************************************************************************/ -/*********************** Get set data using its code *************************/ -/*****************************************************************************/ - -void ExaSet_GetDataOfSetByCod (struct ExaSet_Set *Set) - { - MYSQL_RES *mysql_res; - MYSQL_ROW row; - char StrSetInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; - - /***** Trivial check *****/ - if (Set->SetCod <= 0) - { - /* Initialize to empty set */ - ExaSet_ResetSet (Set); - return; - } - - /***** Get data of set of questions from database *****/ - if (DB_QuerySELECT (&mysql_res,"can not get set data", - "SELECT SetCod," // row[0] - "SetInd," // row[1] - "NumQstsToExam," // row[2] - "Title" // row[3] - " FROM exa_sets" - " WHERE SetCod=%ld" - " AND ExaCod=%ld", // Extra check - Set->SetCod,Set->ExaCod)) // Set found... - { - /* Get row */ - row = mysql_fetch_row (mysql_res); - /* - row[0] SetCod - row[1] SetInd - row[2] NumQstsToExam - row[3] Title - */ - /* Get set code (row[0]) */ - Set->SetCod = Str_ConvertStrCodToLongCod (row[0]); - - /* Get set index (row[1]) */ - Set->SetInd = Str_ConvertStrToUnsigned (row[1]); - snprintf (StrSetInd,sizeof (Set->SetInd), - "%u", - Set->SetInd); - - /* Get set index (row[2]) */ - Set->NumQstsToExam = Str_ConvertStrToUnsigned (row[2]); - - /* Get the title of the set (row[3]) */ - Str_Copy (Set->Title,row[3], - ExaSet_MAX_BYTES_TITLE); - } - else - /* Initialize to empty set */ - ExaSet_ResetSet (Set); - - /* Free structure that stores the query result */ - DB_FreeMySQLResult (&mysql_res); - } - /*****************************************************************************/ /********************** Get exam data using its code *************************/ /*****************************************************************************/ @@ -1249,7 +1065,7 @@ void Exa_FreeListExams (struct Exa_Exams *Exams) /********************** Get exam text from database ************************/ /*****************************************************************************/ -static void Exa_GetExamTxtFromDB (long ExaCod,char Txt[Cns_MAX_BYTES_TEXT + 1]) +void Exa_GetExamTxtFromDB (long ExaCod,char Txt[Cns_MAX_BYTES_TEXT + 1]) { MYSQL_RES *mysql_res; MYSQL_ROW row; @@ -1472,25 +1288,6 @@ void Exa_UnhideExam (void) Exa_ListAllExams (&Exams); } -/*****************************************************************************/ -/************** Check if the title of a set of questions exists **************/ -/*****************************************************************************/ - -static bool ExaSet_CheckIfSimilarSetExists (const struct ExaSet_Set *Set, - const char Title[ExaSet_MAX_BYTES_TITLE + 1]) - { - /***** Get number of set of questions with a field value from database *****/ - return (DB_QueryCOUNT ("can not get similar sets of questions", - "SELECT COUNT(*) FROM exa_sets,exa_exams" - " WHERE exa_sets.ExaCod=%ld AND exa_sets.Title='%s'" - " AND exa_sets.SetCod<>%ld" - " AND exa_sets.ExaCod=exa_exams.ExaCod" - " AND exa_exams.CrsCod=%ld", // Extra check - Set->ExaCod,Title, - Set->SetCod, - Gbl.Hierarchy.Crs.CrsCod) != 0); - } - /*****************************************************************************/ /******************* Check if the title of an exam exists *******************/ /*****************************************************************************/ @@ -1550,10 +1347,10 @@ void Exa_RequestCreatOrEditExam (void) /******************** Put forms to create/edit an exam ***********************/ /*****************************************************************************/ -static void Exa_PutFormsOneExam (struct Exa_Exams *Exams, - struct Exa_Exam *Exam, - struct ExaSet_Set *Set, - bool ItsANewExam) +void Exa_PutFormsOneExam (struct Exa_Exams *Exams, + struct Exa_Exam *Exam, + struct ExaSet_Set *Set, + bool ItsANewExam) { char Txt[Cns_MAX_BYTES_TEXT + 1]; @@ -1579,283 +1376,10 @@ static void Exa_PutFormsOneExam (struct Exa_Exams *Exams, /********************* Put a form to create/edit an exam **********************/ /*****************************************************************************/ -static void ExaSet_PutFormNewSet (struct Exa_Exams *Exams, - struct Exa_Exam *Exam, - struct ExaSet_Set *Set, - unsigned MaxSetInd) - { - // extern const char *Hlp_ASSESSMENT_Exams_new_set; - // extern const char *Hlp_ASSESSMENT_Exams_edit_set; - extern const char *Txt_New_set_of_questions; - extern const char *Txt_Create_set_of_questions; - - /***** Begin form *****/ - Exams->ExaCod = Exam->ExaCod; - Frm_StartForm (ActNewExaSet); - Exa_PutParams (Exams); - - /***** Begin box and table *****/ - Box_BoxTableBegin (NULL,Txt_New_set_of_questions, - NULL,NULL, - NULL,Box_NOT_CLOSABLE,2); - - /***** Table heading *****/ - ExaSet_PutTableHeadingForSets (); - - /***** Begin row *****/ - HTM_TR_Begin (NULL); - - /***** Empty column for buttons *****/ - HTM_TD_Begin ("class=\"BM\""); - HTM_TD_End (); - - /***** Index *****/ - HTM_TD_Begin ("class=\"RM\""); - Tst_WriteNumQst (MaxSetInd + 1); - HTM_TD_End (); - - /***** Title *****/ - HTM_TD_Begin ("class=\"LM\""); - HTM_INPUT_TEXT ("Title",ExaSet_MAX_CHARS_TITLE,Set->Title, - HTM_DONT_SUBMIT_ON_CHANGE, - "id=\"Title\" required=\"required\"" - " class=\"TITLE_DESCRIPTION_WIDTH\""); - HTM_TD_End (); - - /***** Current number of questions in set *****/ - HTM_TD_Begin ("class=\"RM\""); - HTM_Unsigned (0); // New set ==> no questions yet - HTM_TD_End (); - - /***** Number of questions to appear in the exam *****/ - HTM_TD_Begin ("class=\"RM\""); - HTM_INPUT_LONG ("NumQstsToExam",0,UINT_MAX,(long) Set->NumQstsToExam, - HTM_DONT_SUBMIT_ON_CHANGE,false, - "class=\"INPUT_LONG\" required=\"required\""); - HTM_TD_End (); - - /***** End row *****/ - HTM_TR_End (); - - /***** End table, send button and end box *****/ - Box_BoxTableWithButtonEnd (Btn_CREATE_BUTTON,Txt_Create_set_of_questions); - - /***** End form *****/ - Frm_EndForm (); - } - -/*****************************************************************************/ -/**************** Receive form to create a new set of questions **************/ -/*****************************************************************************/ - -void ExaSet_ReceiveFormSet (void) - { - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - bool ItsANewSet; - - /***** Check if I can edit exams *****/ - if (!Exa_CheckIfICanEditExams ()) - Lay_NoPermissionExit (); - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); - ItsANewSet = (Set.SetCod <= 0); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - - /***** If I can edit exams ==> receive set from form *****/ - ExaSet_ReceiveSetFieldsFromForm (&Set); - if (ExaSet_CheckSetTitleReceivedFromForm (&Set,Set.Title)) - { - /***** Create a new exam or update an existing one *****/ - if (ItsANewSet) - ExaSet_CreateSet (&Set); // Add new set to database - else - ExaSet_UpdateSet (&Set); // Update set data in database - } - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -static void ExaSet_ReceiveSetFieldsFromForm (struct ExaSet_Set *Set) - { - /***** Get set title *****/ - Par_GetParToText ("Title",Set->Title,ExaSet_MAX_BYTES_TITLE); - - /***** Get number of questions in set to appear in exam *****/ - Set->NumQstsToExam = (unsigned) Par_GetParToUnsignedLong ("NumQstsToExam", - 0, - UINT_MAX, - 0); - } - -static bool ExaSet_CheckSetTitleReceivedFromForm (const struct ExaSet_Set *Set, - const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]) - { - extern const char *Txt_Already_existed_a_set_of_questions_in_this_exam_with_the_title_X; - extern const char *Txt_You_must_specify_the_title_of_the_set_of_questions; - bool NewTitleIsCorrect; - - /***** Check if title is correct *****/ - NewTitleIsCorrect = true; - if (NewTitle[0]) // If there's an set title - { - /***** Check if old and new titles are the same - (this happens when return is pressed without changes) *****/ - if (strcmp (Set->Title,NewTitle)) // Different titles - { - /* If title of set was in database... */ - if (ExaSet_CheckIfSimilarSetExists (Set,NewTitle)) - { - NewTitleIsCorrect = false; - Ale_ShowAlert (Ale_WARNING,Txt_Already_existed_a_set_of_questions_in_this_exam_with_the_title_X, - Set->Title); - } - } - } - else // If there is not a set title - { - NewTitleIsCorrect = false; - Ale_ShowAlert (Ale_WARNING,Txt_You_must_specify_the_title_of_the_set_of_questions); - } - - return NewTitleIsCorrect; - } - -/*****************************************************************************/ -/************* Receive form to change title of set of questions **************/ -/*****************************************************************************/ - -void ExaSet_ChangeSetTitle (void) - { - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]; - - /***** Check if I can edit exams *****/ - if (!Exa_CheckIfICanEditExams ()) - Lay_NoPermissionExit (); - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - Exams.SetCod = Set.SetCod; - - /***** Get exam and set data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** Receive new title from form *****/ - Par_GetParToText ("Title",NewTitle,ExaSet_MAX_BYTES_TITLE); - - /***** Check if title should be changed *****/ - if (ExaSet_CheckSetTitleReceivedFromForm (&Set,NewTitle)) - { - /* Update the table changing old title by new title */ - ExaSet_UpdateSetTitleDB (&Set,NewTitle); - - /* Update title */ - Str_Copy (Set.Title,NewTitle, - ExaSet_MAX_BYTES_TITLE); - } - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } -/*****************************************************************************/ -/***** Receive form to change number of questions to appear in the exam ******/ -/*****************************************************************************/ - -void ExaSet_ChangeNumQstsToExam (void) - { - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - unsigned NumQstsToExam; - - /***** Check if I can edit exams *****/ - if (!Exa_CheckIfICanEditExams ()) - Lay_NoPermissionExit (); - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - Exams.SetCod = Set.SetCod; - - /***** Get exam and set data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** Get number of questions in set to appear in exam *****/ - NumQstsToExam = (unsigned) Par_GetParToUnsignedLong ("NumQstsToExam", - 0, - UINT_MAX, - 0); - - /***** Check if title should be changed *****/ - if (NumQstsToExam != Set.NumQstsToExam) - { - /* Update the table changing old number by new number */ - ExaSet_UpdateNumQstsToExamDB (&Set,NumQstsToExam); - - /* Update title */ - Set.NumQstsToExam = NumQstsToExam; - } - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -/*****************************************************************************/ -/********************* Put a form to create/edit an exam **********************/ -/*****************************************************************************/ - -static void Exa_PutFormEditionExam (struct Exa_Exams *Exams, - struct Exa_Exam *Exam, - char Txt[Cns_MAX_BYTES_TEXT + 1], - bool ItsANewExam) +void Exa_PutFormEditionExam (struct Exa_Exams *Exams, + struct Exa_Exam *Exam, + char Txt[Cns_MAX_BYTES_TEXT + 1], + bool ItsANewExam) { extern const char *Hlp_ASSESSMENT_Exams_new_exam; extern const char *Hlp_ASSESSMENT_Exams_edit_exam; @@ -2059,93 +1583,6 @@ static bool Exa_CheckExamFieldsReceivedFromForm (const struct Exa_Exam *Exam) return NewExamIsCorrect; } -/*****************************************************************************/ -/********************** Create a new set of questions ************************/ -/*****************************************************************************/ - -static void ExaSet_CreateSet (struct ExaSet_Set *Set) - { - extern const char *Txt_Created_new_set_of_questions_X; - unsigned MaxSetInd; - - /***** Get maximum set index *****/ - MaxSetInd = ExaSet_GetMaxSetIndexInExam (Set->ExaCod); - - /***** Create a new exam *****/ - Set->SetCod = - DB_QueryINSERTandReturnCode ("can not create new set of questions", - "INSERT INTO exa_sets" - " (ExaCod,SetInd,NumQstsToExam,Title)" - " VALUES" - " (%ld,%u,%u,'%s')", - Set->ExaCod, - MaxSetInd + 1, - Set->NumQstsToExam, - Set->Title); - - /***** Write success message *****/ - Ale_ShowAlert (Ale_SUCCESS,Txt_Created_new_set_of_questions_X, - Set->Title); - } - -/*****************************************************************************/ -/******************** Update an existing set of questions ********************/ -/*****************************************************************************/ - -static void ExaSet_UpdateSet (const struct ExaSet_Set *Set) - { - extern const char *Txt_The_set_of_questions_has_been_modified; - - /***** Update the data of the set of questions *****/ - DB_QueryUPDATE ("can not update set of questions", - "UPDATE exa_sets" - " SET ExaCod=%ld," - "SetInd=%u," - "NumQstsToExam=%u," - "Title='%s'" - " WHERE SetCod=%ld", - Set->ExaCod, - Set->SetInd, - Set->NumQstsToExam, - Set->Title, - Set->SetCod); - - /***** Write success message *****/ - Ale_ShowAlert (Ale_SUCCESS,Txt_The_set_of_questions_has_been_modified); - } - -/*****************************************************************************/ -/************************ Update set title in database ***********************/ -/*****************************************************************************/ - -static void ExaSet_UpdateSetTitleDB (const struct ExaSet_Set *Set, - const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]) - { - /***** Update set of questions changing old title by new title *****/ - DB_QueryUPDATE ("can not update the title of a set of questions", - "UPDATE exa_sets SET Title='%s'" - " WHERE SetCod=%ld" - " AND ExaCod=%ld", // Extra check - NewTitle, - Set->SetCod,Set->ExaCod); - } - -/*****************************************************************************/ -/********* Update number of questions to appear in exam in database **********/ -/*****************************************************************************/ - -static void ExaSet_UpdateNumQstsToExamDB (const struct ExaSet_Set *Set, - unsigned NumQstsToExam) - { - /***** Update set of questions changing old number by new number *****/ - DB_QueryUPDATE ("can not update the number of questions to appear in exam", - "UPDATE exa_sets SET NumQstsToExam=%u" - " WHERE SetCod=%ld" - " AND ExaCod=%ld", // Extra check - NumQstsToExam, - Set->SetCod,Set->ExaCod); - } - /*****************************************************************************/ /**************************** Create a new exam ******************************/ /*****************************************************************************/ @@ -2205,207 +1642,6 @@ static void Exa_UpdateExam (struct Exa_Exam *Exam,const char *Txt) Ale_ShowAlert (Ale_SUCCESS,Txt_The_exam_has_been_modified); } -/*****************************************************************************/ -/******************* Get number of questions of an exam *********************/ -/*****************************************************************************/ - -unsigned ExaSet_GetNumSetsExam (long ExaCod) - { - /***** Get number of sets in an exam from database *****/ - return - (unsigned) DB_QueryCOUNT ("can not get number of sets in an exam", - "SELECT COUNT(*) FROM exa_sets" - " WHERE ExaCod=%ld", - ExaCod); - } - -/*****************************************************************************/ -/******************* Get number of questions of an exam *********************/ -/*****************************************************************************/ - -unsigned ExaSet_GetNumQstsExam (long ExaCod) - { - MYSQL_RES *mysql_res; - MYSQL_ROW row; - unsigned NumQsts = 0; - - /***** Get total number of questions to appear in exam *****/ - if (!DB_QuerySELECT (&mysql_res,"can not get number of questions in an exam", - "SELECT SUM(NumQstsToExam) FROM exa_sets" - " WHERE ExaCod=%ld", - ExaCod)) - Lay_ShowErrorAndExit ("Error: wrong question index."); - - /***** Get number of questions (row[0]) *****/ - row = mysql_fetch_row (mysql_res); - if (row[0]) - NumQsts = Str_ConvertStrToUnsigned (row[0]); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - return NumQsts; - } - -/*****************************************************************************/ -/********** Request the creation or edition of an set of questions ***********/ -/*****************************************************************************/ - -void ExaSet_RequestCreatOrEditSet (void) - { - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - bool ItsANewSet; - char Txt[Cns_MAX_BYTES_TEXT + 1]; - - /***** Check if I can edit exams *****/ - if (!Exa_CheckIfICanEditExams ()) - Lay_NoPermissionExit (); - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Exam.ExaCod = Exams.ExaCod; - Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); - ItsANewSet = (Set.SetCod <= 0); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - Exa_GetExamTxtFromDB (Exam.ExaCod,Txt); - - /***** Get set data *****/ - if (ItsANewSet) - /* Initialize to empty set */ - ExaSet_ResetSet (&Set); - else - { - /* Get set data from database */ - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - } - - /***** Put form to edit the exam created or updated *****/ - Exa_PutFormEditionExam (&Exams,&Exam,Txt, - false); // No new exam - } - -/*****************************************************************************/ -/*** Request the selection of questions to be added to a set of questions ****/ -/*****************************************************************************/ - -void ExaSet_ReqSelectQstsToAddToSet (void) - { - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - char Txt[Cns_MAX_BYTES_TEXT + 1]; - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Exam.ExaCod = Exams.ExaCod; - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - Exa_GetExamTxtFromDB (Exam.ExaCod,Txt); - if (!Exa_CheckIfEditable (&Exam)) - Lay_NoPermissionExit (); - - /***** Get set data from database *****/ - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** Show form to select questions for set *****/ - Tst_RequestSelectTestsForSet (&Exams); - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -/*****************************************************************************/ -/**************** List several test questions for selection ******************/ -/*****************************************************************************/ - -void ExaSet_ListQstsToAddToSet (void) - { - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - char Txt[Cns_MAX_BYTES_TEXT + 1]; - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Exam.ExaCod = Exams.ExaCod; - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - Exa_GetExamTxtFromDB (Exam.ExaCod,Txt); - if (!Exa_CheckIfEditable (&Exam)) - Lay_NoPermissionExit (); - - /***** Get set data from database *****/ - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** List several test questions for selection *****/ - Tst_ListQuestionsToSelectForSet (&Exams); - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -/*****************************************************************************/ -/**************** Write parameter with index of set of questions *****************/ -/*****************************************************************************/ - -static void ExaSet_PutParamSetCod (long SetCod) - { - Par_PutHiddenParamUnsigned (NULL,"SetCod",SetCod); - } - /*****************************************************************************/ /****************** Write parameter with index of question *******************/ /*****************************************************************************/ @@ -2430,62 +1666,6 @@ unsigned Exa_GetParamQstInd (void) return (unsigned) QstInd; } -/*****************************************************************************/ -/****************** Get set index given exam and set code ********************/ -/*****************************************************************************/ - -static unsigned ExaSet_GetSetIndFromSetCod (long ExaCod,long SetCod) - { - MYSQL_RES *mysql_res; - MYSQL_ROW row; - long SetInd; - - /***** Get set index from set code *****/ - if (!DB_QuerySELECT (&mysql_res,"can not get set index", - "SELECT SetInd FROM exa_sets" - " WHERE SetCod=%u" - " AND ExaCod=%ld", // Extra check - SetCod,ExaCod)) - Lay_ShowErrorAndExit ("Error: wrong set code."); - - /***** Get set code (row[0]) *****/ - row = mysql_fetch_row (mysql_res); - SetInd = Str_ConvertStrToUnsigned (row[0]); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - return SetInd; - } - -/*****************************************************************************/ -/****************** Get set code given exam and set index ********************/ -/*****************************************************************************/ - -static long ExaSet_GetSetCodFromSetInd (long ExaCod,unsigned SetInd) - { - MYSQL_RES *mysql_res; - MYSQL_ROW row; - long SetCod; - - /***** Get set code from set index *****/ - if (!DB_QuerySELECT (&mysql_res,"can not get set code", - "SELECT SetCod FROM exa_sets" - " WHERE ExaCod=%ld AND SetInd=%u", - ExaCod,SetInd)) - Lay_ShowErrorAndExit ("Error: wrong set index."); - - /***** Get set code (row[0]) *****/ - row = mysql_fetch_row (mysql_res); - if ((SetCod = Str_ConvertStrCodToLongCod (row[0])) <= 0) - Lay_ShowErrorAndExit ("Error: wrong set code."); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - return SetCod; - } - /*****************************************************************************/ /************ Get question code given exam and index of question *************/ /*****************************************************************************/ @@ -2514,103 +1694,6 @@ long Exa_GetQstCodFromQstInd (long ExaCod,unsigned QstInd) return QstCod; } -/*****************************************************************************/ -/********************* Get maximum set index in an exam **********************/ -/*****************************************************************************/ -// Question index can be 1, 2, 3... -// Return 0 if no questions - -static unsigned ExaSet_GetMaxSetIndexInExam (long ExaCod) - { - MYSQL_RES *mysql_res; - MYSQL_ROW row; - unsigned SetInd = 0; - - /***** Get maximum set index in an exam from database *****/ - DB_QuerySELECT (&mysql_res,"can not get max set index", - "SELECT MAX(SetInd)" - " FROM exa_sets" - " WHERE ExaCod=%ld", - ExaCod); - row = mysql_fetch_row (mysql_res); - if (row[0]) // There are sets - if (sscanf (row[0],"%u",&SetInd) != 1) - Lay_ShowErrorAndExit ("Error when getting max set index."); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - return SetInd; - } - -/*****************************************************************************/ -/*********** Get previous set index to a given set index in an exam **********/ -/*****************************************************************************/ -// Input set index can be 1, 2, 3... n-1 -// Return set index will be 1, 2, 3... n if previous set exists, or 0 if no previous set - -static unsigned ExaSet_GetPrevSetIndexInExam (long ExaCod,unsigned SetInd) - { - MYSQL_RES *mysql_res; - MYSQL_ROW row; - unsigned PrevSetInd = 0; - - /***** Get previous set index in an exam from database *****/ - // Although indexes are always continuous... - // ...this implementation works even with non continuous indexes - if (!DB_QuerySELECT (&mysql_res,"can not get previous set index", - "SELECT MAX(SetInd) FROM exa_sets" - " WHERE ExaCod=%ld AND SetInd<%u", - ExaCod,SetInd)) - Lay_ShowErrorAndExit ("Error: previous set index not found."); - - /***** Get previous set index (row[0]) *****/ - row = mysql_fetch_row (mysql_res); - if (row) - if (row[0]) - if (sscanf (row[0],"%u",&PrevSetInd) != 1) - Lay_ShowErrorAndExit ("Error when getting previous set index."); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - return PrevSetInd; - } - -/*****************************************************************************/ -/*************** Get next set index to a given index in an exam **************/ -/*****************************************************************************/ -// Input set index can be 0, 1, 2, 3... n-1 -// Return set index will be 1, 2, 3... n if next set exists, or 0 if no next set - -static unsigned ExaSet_GetNextSetIndexInExam (long ExaCod,unsigned SetInd) - { - MYSQL_RES *mysql_res; - MYSQL_ROW row; - unsigned NextSetInd = ExaEvt_AFTER_LAST_QUESTION; // End of sets has been reached - - /***** Get next set index in an exam from database *****/ - // Although indexes are always continuous... - // ...this implementation works even with non continuous indexes - if (!DB_QuerySELECT (&mysql_res,"can not get next set index", - "SELECT MIN(SetInd) FROM exa_sets" - " WHERE ExaCod=%ld AND SetInd>%u", - ExaCod,SetInd)) - Lay_ShowErrorAndExit ("Error: next set index not found."); - - /***** Get next set index (row[0]) *****/ - row = mysql_fetch_row (mysql_res); - if (row) - if (row[0]) - if (sscanf (row[0],"%u",&NextSetInd) != 1) - Lay_ShowErrorAndExit ("Error when getting next set index."); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - return NextSetInd; - } - /*****************************************************************************/ /*********** Get previous question index to a given index in an exam **********/ /*****************************************************************************/ @@ -2679,320 +1762,6 @@ unsigned Exa_GetNextQuestionIndexInExam (long ExaCod,unsigned QstInd) return NextQstInd; } -/*****************************************************************************/ -/************************* List the sets of an exam **************************/ -/*****************************************************************************/ - -static void ExaSet_ListExamSets (struct Exa_Exams *Exams, - struct Exa_Exam *Exam, - struct ExaSet_Set *Set) - { - extern const char *Hlp_ASSESSMENT_Exams_question_sets; - extern const char *Txt_Sets_of_questions; - MYSQL_RES *mysql_res; - unsigned MaxSetInd; - unsigned NumSets; - bool ICanEditSets = Exa_CheckIfEditable (Exam); - - /***** Get maximum set index *****/ - MaxSetInd = ExaSet_GetMaxSetIndexInExam (Exam->ExaCod); - - /***** Get data of set of questions from database *****/ - NumSets = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get sets of questions", - "SELECT SetCod," // row[0] - "SetInd," // row[1] - "NumQstsToExam," // row[2] - "Title" // row[3] - " FROM exa_sets" - " WHERE ExaCod=%ld" - " ORDER BY SetInd", - Exam->ExaCod); - - /***** Begin box *****/ - Exams->ExaCod = Exam->ExaCod; - Box_BoxBegin (NULL,Txt_Sets_of_questions, - NULL,NULL, - Hlp_ASSESSMENT_Exams_question_sets,Box_NOT_CLOSABLE); - - /***** Show table with sets *****/ - if (NumSets) - ExaSet_ListOneOrMoreSetsForEdition (Exams,Exam, - MaxSetInd, - NumSets,mysql_res, - ICanEditSets); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - /***** Put forms to create/edit a set *****/ - ExaSet_PutFormNewSet (Exams,Exam,Set,MaxSetInd); - - /***** End box *****/ - Box_BoxEnd (); - } - -/*****************************************************************************/ -/************************ List the questions of an exam ***********************/ -/*****************************************************************************/ - -static void ExaSet_ListSetQuestions (struct Exa_Exams *Exams, - const struct Exa_Exam *Exam, - const struct ExaSet_Set *Set) - { - extern const char *Hlp_ASSESSMENT_Exams_questions; - extern const char *Txt_Questions; - MYSQL_RES *mysql_res; - unsigned NumQsts; - bool ICanEditQuestions = Exa_CheckIfEditable (Exam); - - /***** Get data of questions from database *****/ - NumQsts = (unsigned) - DB_QuerySELECT (&mysql_res,"can not get exam questions", - "SELECT exa_questions.QstCod" // row[0] - " FROM exa_questions LEFT JOIN tst_questions" // LEFT JOIN because the question could be removed in table of test questions - " ON (exa_questions.QstCod=tst_questions.QstCod)" - " WHERE exa_questions.SetCod=%ld" - " ORDER BY tst_questions.Stem", - Set->SetCod); - - /***** Begin box *****/ - if (ICanEditQuestions) - Box_BoxBegin (NULL,Txt_Questions, - Exa_PutIconToAddNewQuestions,Exams, - Hlp_ASSESSMENT_Exams_questions,Box_NOT_CLOSABLE); - else - Box_BoxBegin (NULL,Txt_Questions, - NULL,NULL, - Hlp_ASSESSMENT_Exams_questions,Box_NOT_CLOSABLE); - - /***** Show table with questions *****/ - if (NumQsts) - ExaSet_ListOneOrMoreQuestionsForEdition (Exams,NumQsts,mysql_res, - ICanEditQuestions); - - /***** Put button to add a new question in this set *****/ - if (ICanEditQuestions) // I can edit questions - Exa_PutButtonToAddNewQuestions (Exams); - - /***** Free structure that stores the query result *****/ - DB_FreeMySQLResult (&mysql_res); - - /***** End box *****/ - Box_BoxEnd (); - } - -/*****************************************************************************/ -/************************* List exam sets for edition ************************/ -/*****************************************************************************/ - -static void ExaSet_ListOneOrMoreSetsForEdition (struct Exa_Exams *Exams, - const struct Exa_Exam *Exam, - unsigned MaxSetInd, - unsigned NumSets, - MYSQL_RES *mysql_res, - bool ICanEditSets) - { - extern const char *Txt_Sets_of_questions; - extern const char *Txt_Move_up_X; - extern const char *Txt_Move_down_X; - extern const char *Txt_Movement_not_allowed; - unsigned NumSet; - struct ExaSet_Set Set; - MYSQL_ROW row; - char *Anchor; - char StrSetInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; - - /***** Trivial check *****/ - if (!NumSets) - return; - - /***** Write the heading *****/ - HTM_TABLE_BeginWideMarginPadding (2); - ExaSet_PutTableHeadingForSets (); - - /***** Write rows *****/ - for (NumSet = 0; - NumSet < NumSets; - NumSet++) - { - Gbl.RowEvenOdd = NumSet % 2; - - /***** Create set of questions *****/ - ExaSet_ResetSet (&Set); - - /***** Get set data *****/ - row = mysql_fetch_row (mysql_res); - /* - row[0] SetCod - row[1] SetInd - row[2] NumQstsToExam - row[3] Title - */ - /* Get set code (row[0]) */ - Set.SetCod = Str_ConvertStrCodToLongCod (row[0]); - - /* Get set index (row[1]) */ - Set.SetInd = Str_ConvertStrToUnsigned (row[1]); - snprintf (StrSetInd,sizeof (Set.SetInd), - "%u", - Set.SetInd); - - /* Get set index (row[2]) */ - Set.NumQstsToExam = Str_ConvertStrToUnsigned (row[2]); - - /* Get the title of the set (row[3]) */ - Str_Copy (Set.Title,row[3], - ExaSet_MAX_BYTES_TITLE); - - /* Initialize context */ - Exams->SetCod = Set.SetCod; - Exams->SetInd = Set.SetInd; - - /***** Build anchor string *****/ - Frm_SetAnchorStr (Set.SetCod,&Anchor); - - /***** Begin first row *****/ - HTM_TR_Begin (NULL); - - /***** Icons *****/ - HTM_TD_Begin ("rowspan=\"2\" class=\"BT%u\"",Gbl.RowEvenOdd); - - /* Put icon to remove the set */ - if (ICanEditSets) - { - Frm_StartForm (ActReqRemExaSet); - ExaSet_PutParamsOneSet (Exams); - Ico_PutIconRemove (); - Frm_EndForm (); - } - else - Ico_PutIconRemovalNotAllowed (); - - /* Put icon to move up the question */ - if (ICanEditSets && Set.SetInd > 1) - { - Lay_PutContextualLinkOnlyIcon (ActUp_ExaSet,Anchor, - ExaSet_PutParamsOneSet,Exams, - "arrow-up.svg", - Str_BuildStringStr (Txt_Move_up_X, - StrSetInd)); - Str_FreeString (); - } - else - Ico_PutIconOff ("arrow-up.svg",Txt_Movement_not_allowed); - - /* Put icon to move down the set */ - if (ICanEditSets && Set.SetInd < MaxSetInd) - { - Lay_PutContextualLinkOnlyIcon (ActDwnExaSet,Anchor, - ExaSet_PutParamsOneSet,Exams, - "arrow-down.svg", - Str_BuildStringStr (Txt_Move_down_X, - StrSetInd)); - Str_FreeString (); - } - else - Ico_PutIconOff ("arrow-down.svg",Txt_Movement_not_allowed); - - HTM_TD_End (); - - /***** Index *****/ - HTM_TD_Begin ("rowspan=\"2\" class=\"RT COLOR%u\"",Gbl.RowEvenOdd); - Tst_WriteNumQst (Set.SetInd); - HTM_TD_End (); - - /***** Title *****/ - HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); - HTM_ARTICLE_Begin (Anchor); - Frm_StartFormAnchor (ActChgTitExaSet,Anchor); - ExaSet_PutParamsOneSet (Exams); - HTM_INPUT_TEXT ("Title",ExaSet_MAX_CHARS_TITLE,Set.Title, - HTM_SUBMIT_ON_CHANGE, - "id=\"Title\" required=\"required\"" - " class=\"TITLE_DESCRIPTION_WIDTH\""); - Frm_EndForm (); - HTM_ARTICLE_End (); - HTM_TD_End (); - - /***** Current number of questions in set *****/ - HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); - HTM_Unsigned (ExaSet_GetNumQstsInSet (Set.SetCod)); - HTM_TD_End (); - - /***** Number of questions to appear in exam *****/ - HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); - Frm_StartFormAnchor (ActChgNumQstExaSet,Anchor); - ExaSet_PutParamsOneSet (Exams); - HTM_INPUT_LONG ("NumQstsToExam",0,UINT_MAX,(long) Set.NumQstsToExam, - HTM_SUBMIT_ON_CHANGE,false, - "class=\"INPUT_LONG\" required=\"required\""); - Frm_EndForm (); - HTM_TD_End (); - - /***** End first row *****/ - HTM_TR_End (); - - /***** Begin second row *****/ - HTM_TR_Begin (NULL); - - /***** Questions *****/ - HTM_TD_Begin ("colspan=\"3\" class=\"LT COLOR%u\"",Gbl.RowEvenOdd); - - /* List questions */ - ExaSet_ListSetQuestions (Exams,Exam,&Set); - - HTM_TD_End (); - - /***** End second row *****/ - HTM_TR_End (); - - /***** Free anchor string *****/ - Frm_FreeAnchorStr (Anchor); - } - - /***** End table *****/ - HTM_TABLE_End (); - } - -/*****************************************************************************/ -/***************** Put table heading for sets of questions *******************/ -/*****************************************************************************/ - -static void ExaSet_PutTableHeadingForSets (void) - { - extern const char *Txt_No_INDEX; - extern const char *Txt_Set_of_questions; - extern const char *Txt_Number_of_questions; - extern const char *Txt_Number_of_questions_in_the_exam; - - /***** Begin row *****/ - HTM_TR_Begin (NULL); - - /***** Header cells *****/ - HTM_TH_Empty (1); - HTM_TH (1,1,"RB",Txt_No_INDEX); - HTM_TH (1,1,"LB",Txt_Set_of_questions); - HTM_TH (1,1,"RB",Txt_Number_of_questions); - HTM_TH (1,1,"RB",Txt_Number_of_questions_in_the_exam); - - /***** End row *****/ - HTM_TR_End (); - } - -/*****************************************************************************/ -/*************************** Reset set of questions **************************/ -/*****************************************************************************/ - -static void ExaSet_ResetSet (struct ExaSet_Set *Set) - { - Set->ExaCod = -1L; - Set->SetCod = -1L; - Set->SetInd = 0; - Set->Title[0] = '\0'; - Set->NumQstsToExam = 0; - } - /*****************************************************************************/ /*************** Put parameter with set code to edit, remove... **************/ /*****************************************************************************/ @@ -3005,663 +1774,12 @@ static void Exa_PutParamSetCod (void *SetCod) // Should be a pointer to long } */ -/*****************************************************************************/ -/********************* List exam questions for edition ***********************/ -/*****************************************************************************/ - -static void ExaSet_ListOneOrMoreQuestionsForEdition (struct Exa_Exams *Exams, - unsigned NumQsts, - MYSQL_RES *mysql_res, - bool ICanEditQuestions) - { - extern const char *Txt_Questions; - extern const char *Txt_No_INDEX; - extern const char *Txt_Code; - extern const char *Txt_Tags; - extern const char *Txt_Question; - unsigned NumQst; - MYSQL_ROW row; - struct Tst_Question Question; - bool QuestionExists; - char *Anchor; - - /***** Build anchor string *****/ - Frm_SetAnchorStr (Exams->SetCod,&Anchor); - - /***** Write the heading *****/ - HTM_TABLE_BeginWideMarginPadding (2); - HTM_TR_Begin (NULL); - - HTM_TH_Empty (1); - - HTM_TH (1,1,"CT",Txt_No_INDEX); - HTM_TH (1,1,"CT",Txt_Code); - HTM_TH (1,1,"CT",Txt_Tags); - HTM_TH (1,1,"CT",Txt_Question); - - HTM_TR_End (); - - /***** Write rows *****/ - for (NumQst = 0; - NumQst < NumQsts; - NumQst++) - { - Gbl.RowEvenOdd = NumQst % 2; - - /***** Create test question *****/ - Tst_QstConstructor (&Question); - - /***** Get question data *****/ - row = mysql_fetch_row (mysql_res); - /* - row[0] QstCod - */ - /* Get question code (row[0]) */ - Exams->QstCod = Question.QstCod = Str_ConvertStrCodToLongCod (row[0]); - - /***** Begin row *****/ - HTM_TR_Begin (NULL); - - /***** Icons *****/ - HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd); - - /* Put icon to remove the question */ - if (ICanEditQuestions) - { - Frm_StartForm (ActReqRemSetQst); - ExaSet_PutParamsOneQst (Exams); - Ico_PutIconRemove (); - Frm_EndForm (); - } - else - Ico_PutIconRemovalNotAllowed (); - - /* Put icon to edit the question */ - if (ICanEditQuestions) - Ico_PutContextualIconToEdit (ActEdiOneTstQst,NULL, - Tst_PutParamQstCod,&Question.QstCod); - - HTM_TD_End (); - - /***** Question *****/ - QuestionExists = Tst_GetQstDataFromDB (&Question); - Tst_ListQuestionForEdition (&Question,NumQst + 1,QuestionExists,Anchor); - - /***** End row *****/ - HTM_TR_End (); - - /***** Destroy test question *****/ - Tst_QstDestructor (&Question); - } - - /***** End table *****/ - HTM_TABLE_End (); - - /***** Free anchor string *****/ - Frm_FreeAnchorStr (Anchor); - } - -/*****************************************************************************/ -/***************** Put icon to add a new questions to exam *******************/ -/*****************************************************************************/ - -static void Exa_PutIconToAddNewQuestions (void *Exams) - { - extern const char *Txt_Add_questions; - - /***** Put form to create a new question *****/ - Ico_PutContextualIconToAdd (ActReqAddQstExaSet,NULL, - Exa_PutParams,Exams, - Txt_Add_questions); - } - -/*****************************************************************************/ -/***************** Put button to add new questions to exam *******************/ -/*****************************************************************************/ - -static void Exa_PutButtonToAddNewQuestions (struct Exa_Exams *Exams) - { - extern const char *Txt_Add_questions; - - Frm_StartForm (ActReqAddQstExaSet); - ExaSet_PutParamsOneSet (Exams); - Btn_PutConfirmButtonInline (Txt_Add_questions); - Frm_EndForm (); - } - -/*****************************************************************************/ -/************* Add selected test questions to set of questions ***************/ -/*****************************************************************************/ - -void ExaSet_AddQstsToSet (void) - { - extern const char *Txt_No_questions_have_been_added; - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - char Txt[Cns_MAX_BYTES_TEXT + 1]; - const char *Ptr; - char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1]; - long QstCod; - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Exam.ExaCod = Exams.ExaCod; - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - Exa_GetExamTxtFromDB (Exam.ExaCod,Txt); - if (!Exa_CheckIfEditable (&Exam)) - Lay_NoPermissionExit (); - - /***** Get set data from database *****/ - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** Get selected questions *****/ - /* Allocate space for selected question codes */ - ExaSet_AllocateListSelectedQuestions (&Exams); - - /* Get question codes */ - Par_GetParMultiToText ("QstCods",Exams.ListQuestions, - ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS); - - /* Check number of questions */ - if (Tst_CountNumQuestionsInList (Exams.ListQuestions)) // If questions selected... - { - /***** Insert questions in database *****/ - Ptr = Exams.ListQuestions; - while (*Ptr) - { - /* Get next code */ - Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG); - if (sscanf (LongStr,"%ld",&QstCod) != 1) - Lay_ShowErrorAndExit ("Wrong question code."); - - /* Insert question in the table of questions */ - DB_QueryINSERT ("can not add question to set", - "INSERT INTO exa_questions" - " (SetCod,QstCod)" - " VALUES" - " (%ld,%ld)", - Set.SetCod,QstCod); - } - } - else - Ale_ShowAlert (Ale_WARNING,Txt_No_questions_have_been_added); - - /***** Free space for selected question codes *****/ - ExaSet_FreeListsSelectedQuestions (&Exams); - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -/*****************************************************************************/ -/****************** Allocate memory for list of questions ********************/ -/*****************************************************************************/ - -static void ExaSet_AllocateListSelectedQuestions (struct Exa_Exams *Exams) - { - if (!Exams->ListQuestions) - { - if ((Exams->ListQuestions = (char *) malloc (ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS + 1)) == NULL) - Lay_NotEnoughMemoryExit (); - Exams->ListQuestions[0] = '\0'; - } - } - -/*****************************************************************************/ -/*********** Free memory used by list of selected question codes *************/ -/*****************************************************************************/ - -static void ExaSet_FreeListsSelectedQuestions (struct Exa_Exams *Exams) - { - if (Exams->ListQuestions) - { - free (Exams->ListQuestions); - Exams->ListQuestions = NULL; - } - } - -/*****************************************************************************/ -/***************** Request the removal of a set of questions *****************/ -/*****************************************************************************/ - -void ExaSet_RequestRemoveSet (void) - { - extern const char *Txt_Do_you_really_want_to_remove_the_set_of_questions_X; - extern const char *Txt_Remove_set_of_questions; - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - if (!Exa_CheckIfEditable (&Exam)) - Lay_NoPermissionExit (); - - /***** Get set data from database *****/ - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** Show question and button to remove question *****/ - Ale_ShowAlertAndButton (ActRemExaSet,NULL,NULL, - ExaSet_PutParamsOneSet,&Exams, - Btn_REMOVE_BUTTON,Txt_Remove_set_of_questions, - Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_set_of_questions_X, - Set.Title); - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -/*****************************************************************************/ -/************************* Remove a set of questions *************************/ -/*****************************************************************************/ - -void ExaSet_RemoveSet (void) - { - extern const char *Txt_Set_of_questions_removed; - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - if (!Exa_CheckIfEditable (&Exam)) - Lay_NoPermissionExit (); - - /***** Get set data from database *****/ - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** Remove the set from all the tables *****/ - /* Remove questions associated to set */ - DB_QueryDELETE ("can not remove questions associated to set", - "DELETE FROM exa_questions" - " USING exa_questions,exa_sets" - " WHERE exa_questions.SetCod=%ld" - " AND exa_questions.SetCod=exa_sets.SetCod" - " AND exa_sets.ExaCod=%ld", // Extra check - Set.SetCod,Set.ExaCod); - - /* Remove the set itself */ - DB_QueryDELETE ("can not remove set", - "DELETE FROM exa_sets" - " WHERE SetCod=%ld" - " AND ExaCod=%ld", // Extra check - Set.SetCod,Set.ExaCod); - if (!mysql_affected_rows (&Gbl.mysql)) - Lay_ShowErrorAndExit ("The set to be removed does not exist."); - - /* Change index of sets greater than this */ - DB_QueryUPDATE ("can not update indexes of sets", - "UPDATE exa_sets SET SetInd=SetInd-1" - " WHERE ExaCod=%ld AND SetInd>%u", - Set.ExaCod,Set.SetInd); - - /***** Write message *****/ - Ale_ShowAlert (Ale_SUCCESS,Txt_Set_of_questions_removed); - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -/*****************************************************************************/ -/************ Move up position of a set of questions in an exam **************/ -/*****************************************************************************/ - -void ExaSet_MoveUpSet (void) - { - extern const char *Txt_Movement_not_allowed; - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - unsigned SetIndTop; - unsigned SetIndBottom; - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - if (!Exa_CheckIfEditable (&Exam)) - Lay_NoPermissionExit (); - - /***** Get set data from database *****/ - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** Get set index *****/ - SetIndBottom = ExaSet_GetSetIndFromSetCod (Exam.ExaCod,Set.SetCod); - - /***** Move up set *****/ - if (SetIndBottom > 1) - { - /* Indexes of sets to be exchanged */ - SetIndTop = ExaSet_GetPrevSetIndexInExam (Exam.ExaCod,SetIndBottom); - if (!SetIndTop) - Lay_ShowErrorAndExit ("Wrong index of set."); - - /* Exchange sets */ - ExaSet_ExchangeSets (Exam.ExaCod,SetIndTop,SetIndBottom); - } - else - Ale_ShowAlert (Ale_WARNING,Txt_Movement_not_allowed); - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -/*****************************************************************************/ -/*********** Move down position of a set of questions in an exam *************/ -/*****************************************************************************/ - -void ExaSet_MoveDownSet (void) - { - extern const char *Txt_Movement_not_allowed; - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - unsigned SetIndTop; - unsigned SetIndBottom; - unsigned MaxSetInd; // 0 if no sets - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - if (!Exa_CheckIfEditable (&Exam)) - Lay_NoPermissionExit (); - - /***** Get set data from database *****/ - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** Get set index *****/ - SetIndTop = ExaSet_GetSetIndFromSetCod (Exam.ExaCod,Set.SetCod); - - /***** Get maximum set index *****/ - MaxSetInd = ExaSet_GetMaxSetIndexInExam (Exam.ExaCod); - - /***** Move down set *****/ - if (SetIndTop < MaxSetInd) - { - /* Indexes of sets to be exchanged */ - SetIndBottom = ExaSet_GetNextSetIndexInExam (Exam.ExaCod,SetIndTop); - if (!SetIndBottom) - Lay_ShowErrorAndExit ("Wrong index of set."); - - /* Exchange sets */ - ExaSet_ExchangeSets (Exam.ExaCod,SetIndTop,SetIndBottom); - } - else - Ale_ShowAlert (Ale_WARNING,Txt_Movement_not_allowed); - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -/*****************************************************************************/ -/********************** Request the removal of a question ********************/ -/*****************************************************************************/ - -void ExaSet_RequestRemoveQstFromSet (void) - { - extern const char *Txt_Do_you_really_want_to_remove_the_question_X; - extern const char *Txt_Remove_question; - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - char *Anchor; - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - if (!Exa_CheckIfEditable (&Exam)) - Lay_NoPermissionExit (); - - /***** Get set data from database *****/ - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** Get question index *****/ - Exams.QstCod = Tst_GetParamQstCod (); - - /***** Build anchor string *****/ - Frm_SetAnchorStr (Set.SetCod,&Anchor); - - /***** Show question and button to remove question *****/ - Ale_ShowAlertAndButton (ActRemExaQst,Anchor,NULL, - ExaSet_PutParamsOneQst,&Exams, - Btn_REMOVE_BUTTON,Txt_Remove_question, - Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_question_X, - Exams.QstCod); - - /***** Free anchor string *****/ - Frm_FreeAnchorStr (Anchor); - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -/*****************************************************************************/ -/****************************** Remove a question ****************************/ -/*****************************************************************************/ - -void ExaSet_RemoveQstFromSet (void) - { - extern const char *Txt_Question_removed; - struct Exa_Exams Exams; - struct Exa_Exam Exam; - struct ExaSet_Set Set; - long QstCod; - - /***** Reset exams context *****/ - Exa_ResetExams (&Exams); - Exa_ResetExam (&Exam); - ExaSet_ResetSet (&Set); - - /***** Get parameters *****/ - Exa_GetParams (&Exams); - if (Exams.ExaCod <= 0) - Lay_WrongExamExit (); - Set.ExaCod = Exam.ExaCod = Exams.ExaCod; - Set.SetCod = ExaSet_GetParamSetCod (); - if (Set.SetCod <= 0) - Lay_WrongSetExit (); - - /***** Get exam data from database *****/ - Exa_GetDataOfExamByCod (&Exam); - Exams.ExaCod = Exam.ExaCod; - if (!Exa_CheckIfEditable (&Exam)) - Lay_NoPermissionExit (); - - /***** Get set data from database *****/ - ExaSet_GetDataOfSetByCod (&Set); - Exams.SetCod = Set.SetCod; - - /***** Get question index *****/ - QstCod = Tst_GetParamQstCod (); - - /***** Remove the question from set *****/ - /* Remove the question itself */ - DB_QueryDELETE ("can not remove a question from a set", - "DELETE FROM exa_questions" - " WHERE SetCod=%ld AND QstCod=%ld", - Set.SetCod,QstCod); - if (!mysql_affected_rows (&Gbl.mysql)) - Lay_ShowErrorAndExit ("The question to be removed does not exist."); - - /***** Write message *****/ - Ale_ShowAlert (Ale_SUCCESS,Txt_Question_removed); - - /***** Show current exam and its sets *****/ - Exa_PutFormsOneExam (&Exams,&Exam,&Set, - false); // It's not a new exam - } - -/*****************************************************************************/ -/*********** Exchange the order of two consecutive sets in an exam ***********/ -/*****************************************************************************/ - -static void ExaSet_ExchangeSets (long ExaCod, - unsigned SetIndTop,unsigned SetIndBottom) - { - long SetCodTop; - long SetCodBottom; - - /***** Lock table to make the move atomic *****/ - DB_Query ("can not lock tables to exchange sets of questions", - "LOCK TABLES exa_sets WRITE"); - Gbl.DB.LockedTables = true; - - /***** Get set codes of the sets to be moved *****/ - SetCodTop = ExaSet_GetSetCodFromSetInd (ExaCod,SetIndTop); - SetCodBottom = ExaSet_GetSetCodFromSetInd (ExaCod,SetIndBottom); - - /***** Exchange indexes of sets *****/ - /* - Example: - SetIndTop = 1; SetCodTop = 218 - SetIndBottom = 2; SetCodBottom = 220 - Step 1 Step 2 Step 3 -+--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+ -| SetInd | SetCod | | SetInd | SetCod | | SetInd | SetCod | | SetInd | SetCod | -+--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+ -| 1 | 218 |>| -2 | 218 |>| -2 | 218 |>| 2 | 218 | -| 2 | 220 | | 2 | 220 | | 1 | 220 | | 1 | 220 | -| 3 | 232 | | 3 | 232 | | 3 | 232 | | 3 | 232 | -+--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+ - */ - /* Step 1: change temporarily top index to minus bottom index - in order to not repeat unique index (ExaCod,SetInd) */ - DB_QueryUPDATE ("can not exchange indexes of sets", - "UPDATE exa_sets SET SetInd=-%u" - " WHERE ExaCod=%ld AND SetCod=%ld", - SetIndBottom, - ExaCod,SetCodTop); - - /* Step 2: change bottom index to old top index */ - DB_QueryUPDATE ("can not exchange indexes of sets", - "UPDATE exa_sets SET SetInd=%u" - " WHERE ExaCod=%ld AND SetCod=%ld", - SetIndTop, - ExaCod,SetCodBottom); - - /* Step 3: change top index to old bottom index */ - DB_QueryUPDATE ("can not exchange indexes of sets", - "UPDATE exa_sets SET SetInd=%u" - " WHERE ExaCod=%ld AND SetCod=%ld", - SetIndBottom, - ExaCod,SetCodTop); - - /***** Unlock table *****/ - Gbl.DB.LockedTables = false; // Set to false before the following unlock... - // ...to not retry the unlock if error in unlocking - DB_Query ("can not unlock tables after exchanging sets of questions", - "UNLOCK TABLES"); - } - /*****************************************************************************/ /*********** Get number of events and check is edition is possible **********/ /*****************************************************************************/ // Before calling this function, number of events must be calculated -static bool Exa_CheckIfEditable (const struct Exa_Exam *Exam) +bool Exa_CheckIfEditable (const struct Exa_Exam *Exam) { if (Exa_CheckIfICanEditExams ()) /***** Questions are editable only if exam has no events *****/ diff --git a/swad_exam.h b/swad_exam.h index 309da2d9..215a9b82 100644 --- a/swad_exam.h +++ b/swad_exam.h @@ -45,6 +45,9 @@ void Exa_ResetExams (struct Exa_Exams *Exams); void Exa_ResetExam (struct Exa_Exam *Exam); void Exa_SeeAllExams (void); + +bool Exa_CheckIfICanEditExams (void); + void Exa_SeeOneExam (void); void Exa_ShowOnlyOneExam (struct Exa_Exams *Exams, struct Exa_Exam *Exam, @@ -57,11 +60,9 @@ void Exa_ShowOnlyOneExamBegin (struct Exa_Exams *Exams, void Exa_ShowOnlyOneExamEnd (void); void Exa_SetCurrentExaCod (long ExaCod); -void ExaSet_PutParamsOneSet (void *Exams); void Exa_PutParams (void *Exams); void Exa_PutParamExamCod (long ExaCod); long Exa_GetParamExamCod (void); -long ExaSet_GetParamSetCod (void); void Exa_GetParams (struct Exa_Exams *Exams); void Exa_GetListExams (struct Exa_Exams *Exams,Exa_Order_t SelectedOrder); @@ -70,6 +71,8 @@ void Exa_GetDataOfExamByCod (struct Exa_Exam *Exam); void Exa_GetDataOfExamByFolder (struct Exa_Exam *Exam); void Exa_FreeListExams (struct Exa_Exams *Exams); +void Exa_GetExamTxtFromDB (long ExaCod,char Txt[Cns_MAX_BYTES_TEXT + 1]); + void Exa_AskRemExam (void); void Exa_RemoveExam (void); void Exa_RemoveExamsCrs (long CrsCod); @@ -78,20 +81,17 @@ void Exa_HideExam (void); void Exa_UnhideExam (void); void Exa_RequestCreatOrEditExam (void); - -void ExaSet_ReceiveFormSet (void); -void ExaSet_ChangeSetTitle (void); -void ExaSet_ChangeNumQstsToExam (void); +void Exa_PutFormsOneExam (struct Exa_Exams *Exams, + struct Exa_Exam *Exam, + struct ExaSet_Set *Set, + bool ItsANewExam); +void Exa_PutFormEditionExam (struct Exa_Exams *Exams, + struct Exa_Exam *Exam, + char Txt[Cns_MAX_BYTES_TEXT + 1], + bool ItsANewExam); void Exa_ReceiveFormExam (void); -unsigned ExaSet_GetNumSetsExam (long ExaCod); -unsigned ExaSet_GetNumQstsExam (long ExaCod); - -void ExaSet_RequestCreatOrEditSet (void); -void ExaSet_ReqSelectQstsToAddToSet (void); -void ExaSet_ListQstsToAddToSet (void); - void Exa_PutParamQstInd (unsigned QstInd); unsigned Exa_GetParamQstInd (void); long Exa_GetQstCodFromQstInd (long ExaCod,unsigned QstInd); @@ -99,16 +99,7 @@ long Exa_GetQstCodFromQstInd (long ExaCod,unsigned QstInd); unsigned Exa_GetPrevQuestionIndexInExam (long ExaCod,unsigned QstInd); unsigned Exa_GetNextQuestionIndexInExam (long ExaCod,unsigned QstInd); -void ExaSet_AddQstsToSet (void); - -void ExaSet_RequestRemoveSet (void); -void ExaSet_RemoveSet (void); - -void ExaSet_MoveUpSet (void); -void ExaSet_MoveDownSet (void); - -void ExaSet_RequestRemoveQstFromSet (void); -void ExaSet_RemoveQstFromSet (void); +bool Exa_CheckIfEditable (const struct Exa_Exam *Exam); unsigned Exa_GetNumCoursesWithExams (Hie_Level_t Scope); unsigned Exa_GetNumExams (Hie_Level_t Scope); diff --git a/swad_exam_event.c b/swad_exam_event.c index e6d9c221..9713f764 100644 --- a/swad_exam_event.c +++ b/swad_exam_event.c @@ -37,6 +37,7 @@ #include "swad_exam.h" #include "swad_exam_event.h" #include "swad_exam_result.h" +#include "swad_exam_set.h" #include "swad_exam_type.h" #include "swad_form.h" #include "swad_global.h" diff --git a/swad_exam_set.c b/swad_exam_set.c new file mode 100644 index 00000000..63e5e103 --- /dev/null +++ b/swad_exam_set.c @@ -0,0 +1,1940 @@ +// swad_exam_set.c: set of questions in exams + +/* + SWAD (Shared Workspace At a Distance), + is a web platform developed at the University of Granada (Spain), + and used to support university teaching. + + This file is part of SWAD core. + Copyright (C) 1999-2020 Antonio Caņas Vargas + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General 3 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 DBL_MAX +#include // For PATH_MAX +#include // For NULL +#include // For asprintf +#include // For calloc +#include // For string functions + +#include "swad_database.h" +#include "swad_exam.h" +#include "swad_exam_event.h" +#include "swad_exam_result.h" +#include "swad_exam_set.h" +#include "swad_exam_type.h" +#include "swad_figure.h" +#include "swad_form.h" +#include "swad_global.h" +#include "swad_HTML.h" +#include "swad_match.h" +#include "swad_match_result.h" +#include "swad_pagination.h" +#include "swad_role.h" +#include "swad_test.h" +#include "swad_test_visibility.h" + +/*****************************************************************************/ +/************** External global variables from others modules ****************/ +/*****************************************************************************/ + +extern struct Globals Gbl; + +/*****************************************************************************/ +/***************************** Private constants *****************************/ +/*****************************************************************************/ + +#define ExaSet_MAX_SELECTED_QUESTIONS 10000 +#define ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS (ExaSet_MAX_SELECTED_QUESTIONS * (Cns_MAX_DECIMAL_DIGITS_LONG + 1)) + +/*****************************************************************************/ +/******************************* Private types *******************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/***************************** Private variables *****************************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/***************************** Private prototypes ****************************/ +/*****************************************************************************/ + +static void ExaSet_PutParamsOneQst (void *Exams); + +static unsigned ExaSet_GetNumQstsInSet (long SetCod); + +static bool ExaSet_CheckIfSimilarSetExists (const struct ExaSet_Set *Set, + const char Title[ExaSet_MAX_BYTES_TITLE + 1]); + +static void ExaSet_PutFormNewSet (struct Exa_Exams *Exams, + struct Exa_Exam *Exam, + struct ExaSet_Set *Set, + unsigned MaxSetInd); +static void ExaSet_ReceiveSetFieldsFromForm (struct ExaSet_Set *Set); +static bool ExaSet_CheckSetTitleReceivedFromForm (const struct ExaSet_Set *Set, + const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]); + +static void ExaSet_CreateSet (struct ExaSet_Set *Set); +static void ExaSet_UpdateSet (const struct ExaSet_Set *Set); +static void ExaSet_UpdateSetTitleDB (const struct ExaSet_Set *Set, + const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]); +static void ExaSet_UpdateNumQstsToExamDB (const struct ExaSet_Set *Set, + unsigned NumQstsToExam); + +static void ExaSet_PutParamSetCod (long SetCod); + +static unsigned ExaSet_GetSetIndFromSetCod (long ExaCod,long SetCod); +static long ExaSet_GetSetCodFromSetInd (long ExaCod,unsigned SetInd); + +static unsigned ExaSet_GetMaxSetIndexInExam (long ExaCod); + +static unsigned ExaSet_GetPrevSetIndexInExam (long ExaCod,unsigned SetInd); +static unsigned ExaSet_GetNextSetIndexInExam (long ExaCod,unsigned SetInd); + +static void ExaSet_ListSetQuestions (struct Exa_Exams *Exams, + const struct Exa_Exam *Exam, + const struct ExaSet_Set *Set); +static void ExaSet_ListOneOrMoreSetsForEdition (struct Exa_Exams *Exams, + const struct Exa_Exam *Exam, + unsigned MaxSetInd, + unsigned NumSets, + MYSQL_RES *mysql_res, + bool ICanEditSets); +static void ExaSet_PutTableHeadingForSets (void); + +static void ExaSet_ListOneOrMoreQuestionsForEdition (struct Exa_Exams *Exams, + unsigned NumQsts, + MYSQL_RES *mysql_res, + bool ICanEditQuestions); + +static void ExaSet_AllocateListSelectedQuestions (struct Exa_Exams *Exams); +static void ExaSet_FreeListsSelectedQuestions (struct Exa_Exams *Exams); + +static void ExaSet_ExchangeSets (long ExaCod, + unsigned SetIndTop,unsigned SetIndBottom); + +static void ExaSet_PutIconToAddNewQuestions (void *Exams); +static void ExaSet_PutButtonToAddNewQuestions (struct Exa_Exams *Exams); + +/*****************************************************************************/ +/************ Put parameter to move/remove one set of questions **************/ +/*****************************************************************************/ + +void ExaSet_PutParamsOneSet (void *Exams) + { + if (Exams) + { + Exa_PutParams (Exams); + ExaSet_PutParamSetCod (((struct Exa_Exams *) Exams)->SetCod); + } + } + +/*****************************************************************************/ +/**************** Put parameter to move/remove one question ******************/ +/*****************************************************************************/ + +static void ExaSet_PutParamsOneQst (void *Exams) + { + ExaSet_PutParamsOneSet (Exams); + Tst_PutParamQstCod (&(((struct Exa_Exams *) Exams)->QstCod)); + } + +/*****************************************************************************/ +/********************** Get parameter with code of set ***********************/ +/*****************************************************************************/ + +long ExaSet_GetParamSetCod (void) + { + /***** Get code of set *****/ + return Par_GetParToLong ("SetCod"); + } + +/*****************************************************************************/ +/********************* Get number of questions in a set **********************/ +/*****************************************************************************/ + +static unsigned ExaSet_GetNumQstsInSet (long SetCod) + { + /***** Get number of questions in set from database *****/ + return + (unsigned) DB_QueryCOUNT ("can not get number of questions in a set", + "SELECT COUNT(*) FROM exa_questions" + " WHERE SetCod=%ld", + SetCod); + } + +/*****************************************************************************/ +/*********************** Get set data using its code *************************/ +/*****************************************************************************/ + +void ExaSet_GetDataOfSetByCod (struct ExaSet_Set *Set) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + char StrSetInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; + + /***** Trivial check *****/ + if (Set->SetCod <= 0) + { + /* Initialize to empty set */ + ExaSet_ResetSet (Set); + return; + } + + /***** Get data of set of questions from database *****/ + if (DB_QuerySELECT (&mysql_res,"can not get set data", + "SELECT SetCod," // row[0] + "SetInd," // row[1] + "NumQstsToExam," // row[2] + "Title" // row[3] + " FROM exa_sets" + " WHERE SetCod=%ld" + " AND ExaCod=%ld", // Extra check + Set->SetCod,Set->ExaCod)) // Set found... + { + /* Get row */ + row = mysql_fetch_row (mysql_res); + /* + row[0] SetCod + row[1] SetInd + row[2] NumQstsToExam + row[3] Title + */ + /* Get set code (row[0]) */ + Set->SetCod = Str_ConvertStrCodToLongCod (row[0]); + + /* Get set index (row[1]) */ + Set->SetInd = Str_ConvertStrToUnsigned (row[1]); + snprintf (StrSetInd,sizeof (Set->SetInd), + "%u", + Set->SetInd); + + /* Get set index (row[2]) */ + Set->NumQstsToExam = Str_ConvertStrToUnsigned (row[2]); + + /* Get the title of the set (row[3]) */ + Str_Copy (Set->Title,row[3], + ExaSet_MAX_BYTES_TITLE); + } + else + /* Initialize to empty set */ + ExaSet_ResetSet (Set); + + /* Free structure that stores the query result */ + DB_FreeMySQLResult (&mysql_res); + } + +/*****************************************************************************/ +/************** Check if the title of a set of questions exists **************/ +/*****************************************************************************/ + +static bool ExaSet_CheckIfSimilarSetExists (const struct ExaSet_Set *Set, + const char Title[ExaSet_MAX_BYTES_TITLE + 1]) + { + /***** Get number of set of questions with a field value from database *****/ + return (DB_QueryCOUNT ("can not get similar sets of questions", + "SELECT COUNT(*) FROM exa_sets,exa_exams" + " WHERE exa_sets.ExaCod=%ld AND exa_sets.Title='%s'" + " AND exa_sets.SetCod<>%ld" + " AND exa_sets.ExaCod=exa_exams.ExaCod" + " AND exa_exams.CrsCod=%ld", // Extra check + Set->ExaCod,Title, + Set->SetCod, + Gbl.Hierarchy.Crs.CrsCod) != 0); + } + +/*****************************************************************************/ +/********************* Put a form to create/edit an exam **********************/ +/*****************************************************************************/ + +static void ExaSet_PutFormNewSet (struct Exa_Exams *Exams, + struct Exa_Exam *Exam, + struct ExaSet_Set *Set, + unsigned MaxSetInd) + { + // extern const char *Hlp_ASSESSMENT_Exams_new_set; + // extern const char *Hlp_ASSESSMENT_Exams_edit_set; + extern const char *Txt_New_set_of_questions; + extern const char *Txt_Create_set_of_questions; + + /***** Begin form *****/ + Exams->ExaCod = Exam->ExaCod; + Frm_StartForm (ActNewExaSet); + Exa_PutParams (Exams); + + /***** Begin box and table *****/ + Box_BoxTableBegin (NULL,Txt_New_set_of_questions, + NULL,NULL, + NULL,Box_NOT_CLOSABLE,2); + + /***** Table heading *****/ + ExaSet_PutTableHeadingForSets (); + + /***** Begin row *****/ + HTM_TR_Begin (NULL); + + /***** Empty column for buttons *****/ + HTM_TD_Begin ("class=\"BM\""); + HTM_TD_End (); + + /***** Index *****/ + HTM_TD_Begin ("class=\"RM\""); + Tst_WriteNumQst (MaxSetInd + 1); + HTM_TD_End (); + + /***** Title *****/ + HTM_TD_Begin ("class=\"LM\""); + HTM_INPUT_TEXT ("Title",ExaSet_MAX_CHARS_TITLE,Set->Title, + HTM_DONT_SUBMIT_ON_CHANGE, + "id=\"Title\" required=\"required\"" + " class=\"TITLE_DESCRIPTION_WIDTH\""); + HTM_TD_End (); + + /***** Current number of questions in set *****/ + HTM_TD_Begin ("class=\"RM\""); + HTM_Unsigned (0); // New set ==> no questions yet + HTM_TD_End (); + + /***** Number of questions to appear in the exam *****/ + HTM_TD_Begin ("class=\"RM\""); + HTM_INPUT_LONG ("NumQstsToExam",0,UINT_MAX,(long) Set->NumQstsToExam, + HTM_DONT_SUBMIT_ON_CHANGE,false, + "class=\"INPUT_LONG\" required=\"required\""); + HTM_TD_End (); + + /***** End row *****/ + HTM_TR_End (); + + /***** End table, send button and end box *****/ + Box_BoxTableWithButtonEnd (Btn_CREATE_BUTTON,Txt_Create_set_of_questions); + + /***** End form *****/ + Frm_EndForm (); + } + +/*****************************************************************************/ +/**************** Receive form to create a new set of questions **************/ +/*****************************************************************************/ + +void ExaSet_ReceiveFormSet (void) + { + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + bool ItsANewSet; + + /***** Check if I can edit exams *****/ + if (!Exa_CheckIfICanEditExams ()) + Lay_NoPermissionExit (); + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); + ItsANewSet = (Set.SetCod <= 0); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + + /***** If I can edit exams ==> receive set from form *****/ + ExaSet_ReceiveSetFieldsFromForm (&Set); + if (ExaSet_CheckSetTitleReceivedFromForm (&Set,Set.Title)) + { + /***** Create a new exam or update an existing one *****/ + if (ItsANewSet) + ExaSet_CreateSet (&Set); // Add new set to database + else + ExaSet_UpdateSet (&Set); // Update set data in database + } + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +static void ExaSet_ReceiveSetFieldsFromForm (struct ExaSet_Set *Set) + { + /***** Get set title *****/ + Par_GetParToText ("Title",Set->Title,ExaSet_MAX_BYTES_TITLE); + + /***** Get number of questions in set to appear in exam *****/ + Set->NumQstsToExam = (unsigned) Par_GetParToUnsignedLong ("NumQstsToExam", + 0, + UINT_MAX, + 0); + } + +static bool ExaSet_CheckSetTitleReceivedFromForm (const struct ExaSet_Set *Set, + const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]) + { + extern const char *Txt_Already_existed_a_set_of_questions_in_this_exam_with_the_title_X; + extern const char *Txt_You_must_specify_the_title_of_the_set_of_questions; + bool NewTitleIsCorrect; + + /***** Check if title is correct *****/ + NewTitleIsCorrect = true; + if (NewTitle[0]) // If there's an set title + { + /***** Check if old and new titles are the same + (this happens when return is pressed without changes) *****/ + if (strcmp (Set->Title,NewTitle)) // Different titles + { + /* If title of set was in database... */ + if (ExaSet_CheckIfSimilarSetExists (Set,NewTitle)) + { + NewTitleIsCorrect = false; + Ale_ShowAlert (Ale_WARNING,Txt_Already_existed_a_set_of_questions_in_this_exam_with_the_title_X, + Set->Title); + } + } + } + else // If there is not a set title + { + NewTitleIsCorrect = false; + Ale_ShowAlert (Ale_WARNING,Txt_You_must_specify_the_title_of_the_set_of_questions); + } + + return NewTitleIsCorrect; + } + +/*****************************************************************************/ +/************* Receive form to change title of set of questions **************/ +/*****************************************************************************/ + +void ExaSet_ChangeSetTitle (void) + { + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]; + + /***** Check if I can edit exams *****/ + if (!Exa_CheckIfICanEditExams ()) + Lay_NoPermissionExit (); + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + Exams.SetCod = Set.SetCod; + + /***** Get exam and set data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** Receive new title from form *****/ + Par_GetParToText ("Title",NewTitle,ExaSet_MAX_BYTES_TITLE); + + /***** Check if title should be changed *****/ + if (ExaSet_CheckSetTitleReceivedFromForm (&Set,NewTitle)) + { + /* Update the table changing old title by new title */ + ExaSet_UpdateSetTitleDB (&Set,NewTitle); + + /* Update title */ + Str_Copy (Set.Title,NewTitle, + ExaSet_MAX_BYTES_TITLE); + } + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } +/*****************************************************************************/ +/***** Receive form to change number of questions to appear in the exam ******/ +/*****************************************************************************/ + +void ExaSet_ChangeNumQstsToExam (void) + { + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + unsigned NumQstsToExam; + + /***** Check if I can edit exams *****/ + if (!Exa_CheckIfICanEditExams ()) + Lay_NoPermissionExit (); + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + Exams.SetCod = Set.SetCod; + + /***** Get exam and set data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** Get number of questions in set to appear in exam *****/ + NumQstsToExam = (unsigned) Par_GetParToUnsignedLong ("NumQstsToExam", + 0, + UINT_MAX, + 0); + + /***** Check if title should be changed *****/ + if (NumQstsToExam != Set.NumQstsToExam) + { + /* Update the table changing old number by new number */ + ExaSet_UpdateNumQstsToExamDB (&Set,NumQstsToExam); + + /* Update title */ + Set.NumQstsToExam = NumQstsToExam; + } + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +/*****************************************************************************/ +/********************** Create a new set of questions ************************/ +/*****************************************************************************/ + +static void ExaSet_CreateSet (struct ExaSet_Set *Set) + { + extern const char *Txt_Created_new_set_of_questions_X; + unsigned MaxSetInd; + + /***** Get maximum set index *****/ + MaxSetInd = ExaSet_GetMaxSetIndexInExam (Set->ExaCod); + + /***** Create a new exam *****/ + Set->SetCod = + DB_QueryINSERTandReturnCode ("can not create new set of questions", + "INSERT INTO exa_sets" + " (ExaCod,SetInd,NumQstsToExam,Title)" + " VALUES" + " (%ld,%u,%u,'%s')", + Set->ExaCod, + MaxSetInd + 1, + Set->NumQstsToExam, + Set->Title); + + /***** Write success message *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_Created_new_set_of_questions_X, + Set->Title); + } + +/*****************************************************************************/ +/******************** Update an existing set of questions ********************/ +/*****************************************************************************/ + +static void ExaSet_UpdateSet (const struct ExaSet_Set *Set) + { + extern const char *Txt_The_set_of_questions_has_been_modified; + + /***** Update the data of the set of questions *****/ + DB_QueryUPDATE ("can not update set of questions", + "UPDATE exa_sets" + " SET ExaCod=%ld," + "SetInd=%u," + "NumQstsToExam=%u," + "Title='%s'" + " WHERE SetCod=%ld", + Set->ExaCod, + Set->SetInd, + Set->NumQstsToExam, + Set->Title, + Set->SetCod); + + /***** Write success message *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_The_set_of_questions_has_been_modified); + } + +/*****************************************************************************/ +/************************ Update set title in database ***********************/ +/*****************************************************************************/ + +static void ExaSet_UpdateSetTitleDB (const struct ExaSet_Set *Set, + const char NewTitle[ExaSet_MAX_BYTES_TITLE + 1]) + { + /***** Update set of questions changing old title by new title *****/ + DB_QueryUPDATE ("can not update the title of a set of questions", + "UPDATE exa_sets SET Title='%s'" + " WHERE SetCod=%ld" + " AND ExaCod=%ld", // Extra check + NewTitle, + Set->SetCod,Set->ExaCod); + } + +/*****************************************************************************/ +/********* Update number of questions to appear in exam in database **********/ +/*****************************************************************************/ + +static void ExaSet_UpdateNumQstsToExamDB (const struct ExaSet_Set *Set, + unsigned NumQstsToExam) + { + /***** Update set of questions changing old number by new number *****/ + DB_QueryUPDATE ("can not update the number of questions to appear in exam", + "UPDATE exa_sets SET NumQstsToExam=%u" + " WHERE SetCod=%ld" + " AND ExaCod=%ld", // Extra check + NumQstsToExam, + Set->SetCod,Set->ExaCod); + } + +/*****************************************************************************/ +/******************* Get number of questions of an exam *********************/ +/*****************************************************************************/ + +unsigned ExaSet_GetNumSetsExam (long ExaCod) + { + /***** Get number of sets in an exam from database *****/ + return + (unsigned) DB_QueryCOUNT ("can not get number of sets in an exam", + "SELECT COUNT(*) FROM exa_sets" + " WHERE ExaCod=%ld", + ExaCod); + } + +/*****************************************************************************/ +/******************* Get number of questions of an exam *********************/ +/*****************************************************************************/ + +unsigned ExaSet_GetNumQstsExam (long ExaCod) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NumQsts = 0; + + /***** Get total number of questions to appear in exam *****/ + if (!DB_QuerySELECT (&mysql_res,"can not get number of questions in an exam", + "SELECT SUM(NumQstsToExam) FROM exa_sets" + " WHERE ExaCod=%ld", + ExaCod)) + Lay_ShowErrorAndExit ("Error: wrong question index."); + + /***** Get number of questions (row[0]) *****/ + row = mysql_fetch_row (mysql_res); + if (row[0]) + NumQsts = Str_ConvertStrToUnsigned (row[0]); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return NumQsts; + } + +/*****************************************************************************/ +/********** Request the creation or edition of an set of questions ***********/ +/*****************************************************************************/ + +void ExaSet_RequestCreatOrEditSet (void) + { + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + bool ItsANewSet; + char Txt[Cns_MAX_BYTES_TEXT + 1]; + + /***** Check if I can edit exams *****/ + if (!Exa_CheckIfICanEditExams ()) + Lay_NoPermissionExit (); + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Exam.ExaCod = Exams.ExaCod; + Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); + ItsANewSet = (Set.SetCod <= 0); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + Exa_GetExamTxtFromDB (Exam.ExaCod,Txt); + + /***** Get set data *****/ + if (ItsANewSet) + /* Initialize to empty set */ + ExaSet_ResetSet (&Set); + else + { + /* Get set data from database */ + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + } + + /***** Put form to edit the exam created or updated *****/ + Exa_PutFormEditionExam (&Exams,&Exam,Txt, + false); // No new exam + } + +/*****************************************************************************/ +/*** Request the selection of questions to be added to a set of questions ****/ +/*****************************************************************************/ + +void ExaSet_ReqSelectQstsToAddToSet (void) + { + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + char Txt[Cns_MAX_BYTES_TEXT + 1]; + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Exam.ExaCod = Exams.ExaCod; + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + Exa_GetExamTxtFromDB (Exam.ExaCod,Txt); + if (!Exa_CheckIfEditable (&Exam)) + Lay_NoPermissionExit (); + + /***** Get set data from database *****/ + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** Show form to select questions for set *****/ + Tst_RequestSelectTestsForSet (&Exams); + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +/*****************************************************************************/ +/**************** List several test questions for selection ******************/ +/*****************************************************************************/ + +void ExaSet_ListQstsToAddToSet (void) + { + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + char Txt[Cns_MAX_BYTES_TEXT + 1]; + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Exam.ExaCod = Exams.ExaCod; + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + Exa_GetExamTxtFromDB (Exam.ExaCod,Txt); + if (!Exa_CheckIfEditable (&Exam)) + Lay_NoPermissionExit (); + + /***** Get set data from database *****/ + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** List several test questions for selection *****/ + Tst_ListQuestionsToSelectForSet (&Exams); + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +/*****************************************************************************/ +/**************** Write parameter with index of set of questions *****************/ +/*****************************************************************************/ + +static void ExaSet_PutParamSetCod (long SetCod) + { + Par_PutHiddenParamUnsigned (NULL,"SetCod",SetCod); + } + +/*****************************************************************************/ +/****************** Get set index given exam and set code ********************/ +/*****************************************************************************/ + +static unsigned ExaSet_GetSetIndFromSetCod (long ExaCod,long SetCod) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + long SetInd; + + /***** Get set index from set code *****/ + if (!DB_QuerySELECT (&mysql_res,"can not get set index", + "SELECT SetInd FROM exa_sets" + " WHERE SetCod=%u" + " AND ExaCod=%ld", // Extra check + SetCod,ExaCod)) + Lay_ShowErrorAndExit ("Error: wrong set code."); + + /***** Get set code (row[0]) *****/ + row = mysql_fetch_row (mysql_res); + SetInd = Str_ConvertStrToUnsigned (row[0]); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return SetInd; + } + +/*****************************************************************************/ +/****************** Get set code given exam and set index ********************/ +/*****************************************************************************/ + +static long ExaSet_GetSetCodFromSetInd (long ExaCod,unsigned SetInd) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + long SetCod; + + /***** Get set code from set index *****/ + if (!DB_QuerySELECT (&mysql_res,"can not get set code", + "SELECT SetCod FROM exa_sets" + " WHERE ExaCod=%ld AND SetInd=%u", + ExaCod,SetInd)) + Lay_ShowErrorAndExit ("Error: wrong set index."); + + /***** Get set code (row[0]) *****/ + row = mysql_fetch_row (mysql_res); + if ((SetCod = Str_ConvertStrCodToLongCod (row[0])) <= 0) + Lay_ShowErrorAndExit ("Error: wrong set code."); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return SetCod; + } + +/*****************************************************************************/ +/********************* Get maximum set index in an exam **********************/ +/*****************************************************************************/ +// Question index can be 1, 2, 3... +// Return 0 if no questions + +static unsigned ExaSet_GetMaxSetIndexInExam (long ExaCod) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned SetInd = 0; + + /***** Get maximum set index in an exam from database *****/ + DB_QuerySELECT (&mysql_res,"can not get max set index", + "SELECT MAX(SetInd)" + " FROM exa_sets" + " WHERE ExaCod=%ld", + ExaCod); + row = mysql_fetch_row (mysql_res); + if (row[0]) // There are sets + if (sscanf (row[0],"%u",&SetInd) != 1) + Lay_ShowErrorAndExit ("Error when getting max set index."); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return SetInd; + } + +/*****************************************************************************/ +/*********** Get previous set index to a given set index in an exam **********/ +/*****************************************************************************/ +// Input set index can be 1, 2, 3... n-1 +// Return set index will be 1, 2, 3... n if previous set exists, or 0 if no previous set + +static unsigned ExaSet_GetPrevSetIndexInExam (long ExaCod,unsigned SetInd) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned PrevSetInd = 0; + + /***** Get previous set index in an exam from database *****/ + // Although indexes are always continuous... + // ...this implementation works even with non continuous indexes + if (!DB_QuerySELECT (&mysql_res,"can not get previous set index", + "SELECT MAX(SetInd) FROM exa_sets" + " WHERE ExaCod=%ld AND SetInd<%u", + ExaCod,SetInd)) + Lay_ShowErrorAndExit ("Error: previous set index not found."); + + /***** Get previous set index (row[0]) *****/ + row = mysql_fetch_row (mysql_res); + if (row) + if (row[0]) + if (sscanf (row[0],"%u",&PrevSetInd) != 1) + Lay_ShowErrorAndExit ("Error when getting previous set index."); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return PrevSetInd; + } + +/*****************************************************************************/ +/*************** Get next set index to a given index in an exam **************/ +/*****************************************************************************/ +// Input set index can be 0, 1, 2, 3... n-1 +// Return set index will be 1, 2, 3... n if next set exists, or 0 if no next set + +static unsigned ExaSet_GetNextSetIndexInExam (long ExaCod,unsigned SetInd) + { + MYSQL_RES *mysql_res; + MYSQL_ROW row; + unsigned NextSetInd = ExaEvt_AFTER_LAST_QUESTION; // End of sets has been reached + + /***** Get next set index in an exam from database *****/ + // Although indexes are always continuous... + // ...this implementation works even with non continuous indexes + if (!DB_QuerySELECT (&mysql_res,"can not get next set index", + "SELECT MIN(SetInd) FROM exa_sets" + " WHERE ExaCod=%ld AND SetInd>%u", + ExaCod,SetInd)) + Lay_ShowErrorAndExit ("Error: next set index not found."); + + /***** Get next set index (row[0]) *****/ + row = mysql_fetch_row (mysql_res); + if (row) + if (row[0]) + if (sscanf (row[0],"%u",&NextSetInd) != 1) + Lay_ShowErrorAndExit ("Error when getting next set index."); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + return NextSetInd; + } + +/*****************************************************************************/ +/************************* List the sets of an exam **************************/ +/*****************************************************************************/ + +void ExaSet_ListExamSets (struct Exa_Exams *Exams, + struct Exa_Exam *Exam, + struct ExaSet_Set *Set) + { + extern const char *Hlp_ASSESSMENT_Exams_question_sets; + extern const char *Txt_Sets_of_questions; + MYSQL_RES *mysql_res; + unsigned MaxSetInd; + unsigned NumSets; + bool ICanEditSets = Exa_CheckIfEditable (Exam); + + /***** Get maximum set index *****/ + MaxSetInd = ExaSet_GetMaxSetIndexInExam (Exam->ExaCod); + + /***** Get data of set of questions from database *****/ + NumSets = (unsigned) + DB_QuerySELECT (&mysql_res,"can not get sets of questions", + "SELECT SetCod," // row[0] + "SetInd," // row[1] + "NumQstsToExam," // row[2] + "Title" // row[3] + " FROM exa_sets" + " WHERE ExaCod=%ld" + " ORDER BY SetInd", + Exam->ExaCod); + + /***** Begin box *****/ + Exams->ExaCod = Exam->ExaCod; + Box_BoxBegin (NULL,Txt_Sets_of_questions, + NULL,NULL, + Hlp_ASSESSMENT_Exams_question_sets,Box_NOT_CLOSABLE); + + /***** Show table with sets *****/ + if (NumSets) + ExaSet_ListOneOrMoreSetsForEdition (Exams,Exam, + MaxSetInd, + NumSets,mysql_res, + ICanEditSets); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + /***** Put forms to create/edit a set *****/ + ExaSet_PutFormNewSet (Exams,Exam,Set,MaxSetInd); + + /***** End box *****/ + Box_BoxEnd (); + } + +/*****************************************************************************/ +/************************ List the questions of an exam ***********************/ +/*****************************************************************************/ + +static void ExaSet_ListSetQuestions (struct Exa_Exams *Exams, + const struct Exa_Exam *Exam, + const struct ExaSet_Set *Set) + { + extern const char *Hlp_ASSESSMENT_Exams_questions; + extern const char *Txt_Questions; + MYSQL_RES *mysql_res; + unsigned NumQsts; + bool ICanEditQuestions = Exa_CheckIfEditable (Exam); + + /***** Get data of questions from database *****/ + NumQsts = (unsigned) + DB_QuerySELECT (&mysql_res,"can not get exam questions", + "SELECT exa_questions.QstCod" // row[0] + " FROM exa_questions LEFT JOIN tst_questions" // LEFT JOIN because the question could be removed in table of test questions + " ON (exa_questions.QstCod=tst_questions.QstCod)" + " WHERE exa_questions.SetCod=%ld" + " ORDER BY tst_questions.Stem", + Set->SetCod); + + /***** Begin box *****/ + if (ICanEditQuestions) + Box_BoxBegin (NULL,Txt_Questions, + ExaSet_PutIconToAddNewQuestions,Exams, + Hlp_ASSESSMENT_Exams_questions,Box_NOT_CLOSABLE); + else + Box_BoxBegin (NULL,Txt_Questions, + NULL,NULL, + Hlp_ASSESSMENT_Exams_questions,Box_NOT_CLOSABLE); + + /***** Show table with questions *****/ + if (NumQsts) + ExaSet_ListOneOrMoreQuestionsForEdition (Exams,NumQsts,mysql_res, + ICanEditQuestions); + + /***** Put button to add a new question in this set *****/ + if (ICanEditQuestions) // I can edit questions + ExaSet_PutButtonToAddNewQuestions (Exams); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + /***** End box *****/ + Box_BoxEnd (); + } + +/*****************************************************************************/ +/************************* List exam sets for edition ************************/ +/*****************************************************************************/ + +static void ExaSet_ListOneOrMoreSetsForEdition (struct Exa_Exams *Exams, + const struct Exa_Exam *Exam, + unsigned MaxSetInd, + unsigned NumSets, + MYSQL_RES *mysql_res, + bool ICanEditSets) + { + extern const char *Txt_Sets_of_questions; + extern const char *Txt_Move_up_X; + extern const char *Txt_Move_down_X; + extern const char *Txt_Movement_not_allowed; + unsigned NumSet; + struct ExaSet_Set Set; + MYSQL_ROW row; + char *Anchor; + char StrSetInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; + + /***** Trivial check *****/ + if (!NumSets) + return; + + /***** Write the heading *****/ + HTM_TABLE_BeginWideMarginPadding (2); + ExaSet_PutTableHeadingForSets (); + + /***** Write rows *****/ + for (NumSet = 0; + NumSet < NumSets; + NumSet++) + { + Gbl.RowEvenOdd = NumSet % 2; + + /***** Create set of questions *****/ + ExaSet_ResetSet (&Set); + + /***** Get set data *****/ + row = mysql_fetch_row (mysql_res); + /* + row[0] SetCod + row[1] SetInd + row[2] NumQstsToExam + row[3] Title + */ + /* Get set code (row[0]) */ + Set.SetCod = Str_ConvertStrCodToLongCod (row[0]); + + /* Get set index (row[1]) */ + Set.SetInd = Str_ConvertStrToUnsigned (row[1]); + snprintf (StrSetInd,sizeof (Set.SetInd), + "%u", + Set.SetInd); + + /* Get set index (row[2]) */ + Set.NumQstsToExam = Str_ConvertStrToUnsigned (row[2]); + + /* Get the title of the set (row[3]) */ + Str_Copy (Set.Title,row[3], + ExaSet_MAX_BYTES_TITLE); + + /* Initialize context */ + Exams->SetCod = Set.SetCod; + Exams->SetInd = Set.SetInd; + + /***** Build anchor string *****/ + Frm_SetAnchorStr (Set.SetCod,&Anchor); + + /***** Begin first row *****/ + HTM_TR_Begin (NULL); + + /***** Icons *****/ + HTM_TD_Begin ("rowspan=\"2\" class=\"BT%u\"",Gbl.RowEvenOdd); + + /* Put icon to remove the set */ + if (ICanEditSets) + { + Frm_StartForm (ActReqRemExaSet); + ExaSet_PutParamsOneSet (Exams); + Ico_PutIconRemove (); + Frm_EndForm (); + } + else + Ico_PutIconRemovalNotAllowed (); + + /* Put icon to move up the question */ + if (ICanEditSets && Set.SetInd > 1) + { + Lay_PutContextualLinkOnlyIcon (ActUp_ExaSet,Anchor, + ExaSet_PutParamsOneSet,Exams, + "arrow-up.svg", + Str_BuildStringStr (Txt_Move_up_X, + StrSetInd)); + Str_FreeString (); + } + else + Ico_PutIconOff ("arrow-up.svg",Txt_Movement_not_allowed); + + /* Put icon to move down the set */ + if (ICanEditSets && Set.SetInd < MaxSetInd) + { + Lay_PutContextualLinkOnlyIcon (ActDwnExaSet,Anchor, + ExaSet_PutParamsOneSet,Exams, + "arrow-down.svg", + Str_BuildStringStr (Txt_Move_down_X, + StrSetInd)); + Str_FreeString (); + } + else + Ico_PutIconOff ("arrow-down.svg",Txt_Movement_not_allowed); + + HTM_TD_End (); + + /***** Index *****/ + HTM_TD_Begin ("rowspan=\"2\" class=\"RT COLOR%u\"",Gbl.RowEvenOdd); + Tst_WriteNumQst (Set.SetInd); + HTM_TD_End (); + + /***** Title *****/ + HTM_TD_Begin ("class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + HTM_ARTICLE_Begin (Anchor); + Frm_StartFormAnchor (ActChgTitExaSet,Anchor); + ExaSet_PutParamsOneSet (Exams); + HTM_INPUT_TEXT ("Title",ExaSet_MAX_CHARS_TITLE,Set.Title, + HTM_SUBMIT_ON_CHANGE, + "id=\"Title\" required=\"required\"" + " class=\"TITLE_DESCRIPTION_WIDTH\""); + Frm_EndForm (); + HTM_ARTICLE_End (); + HTM_TD_End (); + + /***** Current number of questions in set *****/ + HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); + HTM_Unsigned (ExaSet_GetNumQstsInSet (Set.SetCod)); + HTM_TD_End (); + + /***** Number of questions to appear in exam *****/ + HTM_TD_Begin ("class=\"RT COLOR%u\"",Gbl.RowEvenOdd); + Frm_StartFormAnchor (ActChgNumQstExaSet,Anchor); + ExaSet_PutParamsOneSet (Exams); + HTM_INPUT_LONG ("NumQstsToExam",0,UINT_MAX,(long) Set.NumQstsToExam, + HTM_SUBMIT_ON_CHANGE,false, + "class=\"INPUT_LONG\" required=\"required\""); + Frm_EndForm (); + HTM_TD_End (); + + /***** End first row *****/ + HTM_TR_End (); + + /***** Begin second row *****/ + HTM_TR_Begin (NULL); + + /***** Questions *****/ + HTM_TD_Begin ("colspan=\"3\" class=\"LT COLOR%u\"",Gbl.RowEvenOdd); + + /* List questions */ + ExaSet_ListSetQuestions (Exams,Exam,&Set); + + HTM_TD_End (); + + /***** End second row *****/ + HTM_TR_End (); + + /***** Free anchor string *****/ + Frm_FreeAnchorStr (Anchor); + } + + /***** End table *****/ + HTM_TABLE_End (); + } + +/*****************************************************************************/ +/***************** Put table heading for sets of questions *******************/ +/*****************************************************************************/ + +static void ExaSet_PutTableHeadingForSets (void) + { + extern const char *Txt_No_INDEX; + extern const char *Txt_Set_of_questions; + extern const char *Txt_Number_of_questions; + extern const char *Txt_Number_of_questions_in_the_exam; + + /***** Begin row *****/ + HTM_TR_Begin (NULL); + + /***** Header cells *****/ + HTM_TH_Empty (1); + HTM_TH (1,1,"RB",Txt_No_INDEX); + HTM_TH (1,1,"LB",Txt_Set_of_questions); + HTM_TH (1,1,"RB",Txt_Number_of_questions); + HTM_TH (1,1,"RB",Txt_Number_of_questions_in_the_exam); + + /***** End row *****/ + HTM_TR_End (); + } + +/*****************************************************************************/ +/*************************** Reset set of questions **************************/ +/*****************************************************************************/ + +void ExaSet_ResetSet (struct ExaSet_Set *Set) + { + Set->ExaCod = -1L; + Set->SetCod = -1L; + Set->SetInd = 0; + Set->Title[0] = '\0'; + Set->NumQstsToExam = 0; + } + +/*****************************************************************************/ +/********************* List exam questions for edition ***********************/ +/*****************************************************************************/ + +static void ExaSet_ListOneOrMoreQuestionsForEdition (struct Exa_Exams *Exams, + unsigned NumQsts, + MYSQL_RES *mysql_res, + bool ICanEditQuestions) + { + extern const char *Txt_Questions; + extern const char *Txt_No_INDEX; + extern const char *Txt_Code; + extern const char *Txt_Tags; + extern const char *Txt_Question; + unsigned NumQst; + MYSQL_ROW row; + struct Tst_Question Question; + bool QuestionExists; + char *Anchor; + + /***** Build anchor string *****/ + Frm_SetAnchorStr (Exams->SetCod,&Anchor); + + /***** Write the heading *****/ + HTM_TABLE_BeginWideMarginPadding (2); + HTM_TR_Begin (NULL); + + HTM_TH_Empty (1); + + HTM_TH (1,1,"CT",Txt_No_INDEX); + HTM_TH (1,1,"CT",Txt_Code); + HTM_TH (1,1,"CT",Txt_Tags); + HTM_TH (1,1,"CT",Txt_Question); + + HTM_TR_End (); + + /***** Write rows *****/ + for (NumQst = 0; + NumQst < NumQsts; + NumQst++) + { + Gbl.RowEvenOdd = NumQst % 2; + + /***** Create test question *****/ + Tst_QstConstructor (&Question); + + /***** Get question data *****/ + row = mysql_fetch_row (mysql_res); + /* + row[0] QstCod + */ + /* Get question code (row[0]) */ + Exams->QstCod = Question.QstCod = Str_ConvertStrCodToLongCod (row[0]); + + /***** Begin row *****/ + HTM_TR_Begin (NULL); + + /***** Icons *****/ + HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd); + + /* Put icon to remove the question */ + if (ICanEditQuestions) + { + Frm_StartForm (ActReqRemSetQst); + ExaSet_PutParamsOneQst (Exams); + Ico_PutIconRemove (); + Frm_EndForm (); + } + else + Ico_PutIconRemovalNotAllowed (); + + /* Put icon to edit the question */ + if (ICanEditQuestions) + Ico_PutContextualIconToEdit (ActEdiOneTstQst,NULL, + Tst_PutParamQstCod,&Question.QstCod); + + HTM_TD_End (); + + /***** Question *****/ + QuestionExists = Tst_GetQstDataFromDB (&Question); + Tst_ListQuestionForEdition (&Question,NumQst + 1,QuestionExists,Anchor); + + /***** End row *****/ + HTM_TR_End (); + + /***** Destroy test question *****/ + Tst_QstDestructor (&Question); + } + + /***** End table *****/ + HTM_TABLE_End (); + + /***** Free anchor string *****/ + Frm_FreeAnchorStr (Anchor); + } + +/*****************************************************************************/ +/************* Add selected test questions to set of questions ***************/ +/*****************************************************************************/ + +void ExaSet_AddQstsToSet (void) + { + extern const char *Txt_No_questions_have_been_added; + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + char Txt[Cns_MAX_BYTES_TEXT + 1]; + const char *Ptr; + char LongStr[Cns_MAX_DECIMAL_DIGITS_LONG + 1]; + long QstCod; + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Exam.ExaCod = Exams.ExaCod; + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + Exa_GetExamTxtFromDB (Exam.ExaCod,Txt); + if (!Exa_CheckIfEditable (&Exam)) + Lay_NoPermissionExit (); + + /***** Get set data from database *****/ + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** Get selected questions *****/ + /* Allocate space for selected question codes */ + ExaSet_AllocateListSelectedQuestions (&Exams); + + /* Get question codes */ + Par_GetParMultiToText ("QstCods",Exams.ListQuestions, + ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS); + + /* Check number of questions */ + if (Tst_CountNumQuestionsInList (Exams.ListQuestions)) // If questions selected... + { + /***** Insert questions in database *****/ + Ptr = Exams.ListQuestions; + while (*Ptr) + { + /* Get next code */ + Par_GetNextStrUntilSeparParamMult (&Ptr,LongStr,Cns_MAX_DECIMAL_DIGITS_LONG); + if (sscanf (LongStr,"%ld",&QstCod) != 1) + Lay_ShowErrorAndExit ("Wrong question code."); + + /* Insert question in the table of questions */ + DB_QueryINSERT ("can not add question to set", + "INSERT INTO exa_questions" + " (SetCod,QstCod)" + " VALUES" + " (%ld,%ld)", + Set.SetCod,QstCod); + } + } + else + Ale_ShowAlert (Ale_WARNING,Txt_No_questions_have_been_added); + + /***** Free space for selected question codes *****/ + ExaSet_FreeListsSelectedQuestions (&Exams); + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +/*****************************************************************************/ +/****************** Allocate memory for list of questions ********************/ +/*****************************************************************************/ + +static void ExaSet_AllocateListSelectedQuestions (struct Exa_Exams *Exams) + { + if (!Exams->ListQuestions) + { + if ((Exams->ListQuestions = (char *) malloc (ExaSet_MAX_BYTES_LIST_SELECTED_QUESTIONS + 1)) == NULL) + Lay_NotEnoughMemoryExit (); + Exams->ListQuestions[0] = '\0'; + } + } + +/*****************************************************************************/ +/*********** Free memory used by list of selected question codes *************/ +/*****************************************************************************/ + +static void ExaSet_FreeListsSelectedQuestions (struct Exa_Exams *Exams) + { + if (Exams->ListQuestions) + { + free (Exams->ListQuestions); + Exams->ListQuestions = NULL; + } + } + +/*****************************************************************************/ +/***************** Request the removal of a set of questions *****************/ +/*****************************************************************************/ + +void ExaSet_RequestRemoveSet (void) + { + extern const char *Txt_Do_you_really_want_to_remove_the_set_of_questions_X; + extern const char *Txt_Remove_set_of_questions; + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Exams.SetCod = Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + if (!Exa_CheckIfEditable (&Exam)) + Lay_NoPermissionExit (); + + /***** Get set data from database *****/ + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** Show question and button to remove question *****/ + Ale_ShowAlertAndButton (ActRemExaSet,NULL,NULL, + ExaSet_PutParamsOneSet,&Exams, + Btn_REMOVE_BUTTON,Txt_Remove_set_of_questions, + Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_set_of_questions_X, + Set.Title); + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +/*****************************************************************************/ +/************************* Remove a set of questions *************************/ +/*****************************************************************************/ + +void ExaSet_RemoveSet (void) + { + extern const char *Txt_Set_of_questions_removed; + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + if (!Exa_CheckIfEditable (&Exam)) + Lay_NoPermissionExit (); + + /***** Get set data from database *****/ + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** Remove the set from all the tables *****/ + /* Remove questions associated to set */ + DB_QueryDELETE ("can not remove questions associated to set", + "DELETE FROM exa_questions" + " USING exa_questions,exa_sets" + " WHERE exa_questions.SetCod=%ld" + " AND exa_questions.SetCod=exa_sets.SetCod" + " AND exa_sets.ExaCod=%ld", // Extra check + Set.SetCod,Set.ExaCod); + + /* Remove the set itself */ + DB_QueryDELETE ("can not remove set", + "DELETE FROM exa_sets" + " WHERE SetCod=%ld" + " AND ExaCod=%ld", // Extra check + Set.SetCod,Set.ExaCod); + if (!mysql_affected_rows (&Gbl.mysql)) + Lay_ShowErrorAndExit ("The set to be removed does not exist."); + + /* Change index of sets greater than this */ + DB_QueryUPDATE ("can not update indexes of sets", + "UPDATE exa_sets SET SetInd=SetInd-1" + " WHERE ExaCod=%ld AND SetInd>%u", + Set.ExaCod,Set.SetInd); + + /***** Write message *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_Set_of_questions_removed); + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +/*****************************************************************************/ +/************ Move up position of a set of questions in an exam **************/ +/*****************************************************************************/ + +void ExaSet_MoveUpSet (void) + { + extern const char *Txt_Movement_not_allowed; + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + unsigned SetIndTop; + unsigned SetIndBottom; + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + if (!Exa_CheckIfEditable (&Exam)) + Lay_NoPermissionExit (); + + /***** Get set data from database *****/ + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** Get set index *****/ + SetIndBottom = ExaSet_GetSetIndFromSetCod (Exam.ExaCod,Set.SetCod); + + /***** Move up set *****/ + if (SetIndBottom > 1) + { + /* Indexes of sets to be exchanged */ + SetIndTop = ExaSet_GetPrevSetIndexInExam (Exam.ExaCod,SetIndBottom); + if (!SetIndTop) + Lay_ShowErrorAndExit ("Wrong index of set."); + + /* Exchange sets */ + ExaSet_ExchangeSets (Exam.ExaCod,SetIndTop,SetIndBottom); + } + else + Ale_ShowAlert (Ale_WARNING,Txt_Movement_not_allowed); + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +/*****************************************************************************/ +/*********** Move down position of a set of questions in an exam *************/ +/*****************************************************************************/ + +void ExaSet_MoveDownSet (void) + { + extern const char *Txt_Movement_not_allowed; + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + unsigned SetIndTop; + unsigned SetIndBottom; + unsigned MaxSetInd; // 0 if no sets + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + if (!Exa_CheckIfEditable (&Exam)) + Lay_NoPermissionExit (); + + /***** Get set data from database *****/ + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** Get set index *****/ + SetIndTop = ExaSet_GetSetIndFromSetCod (Exam.ExaCod,Set.SetCod); + + /***** Get maximum set index *****/ + MaxSetInd = ExaSet_GetMaxSetIndexInExam (Exam.ExaCod); + + /***** Move down set *****/ + if (SetIndTop < MaxSetInd) + { + /* Indexes of sets to be exchanged */ + SetIndBottom = ExaSet_GetNextSetIndexInExam (Exam.ExaCod,SetIndTop); + if (!SetIndBottom) + Lay_ShowErrorAndExit ("Wrong index of set."); + + /* Exchange sets */ + ExaSet_ExchangeSets (Exam.ExaCod,SetIndTop,SetIndBottom); + } + else + Ale_ShowAlert (Ale_WARNING,Txt_Movement_not_allowed); + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +/*****************************************************************************/ +/********************** Request the removal of a question ********************/ +/*****************************************************************************/ + +void ExaSet_RequestRemoveQstFromSet (void) + { + extern const char *Txt_Do_you_really_want_to_remove_the_question_X; + extern const char *Txt_Remove_question; + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + char *Anchor; + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + if (!Exa_CheckIfEditable (&Exam)) + Lay_NoPermissionExit (); + + /***** Get set data from database *****/ + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** Get question index *****/ + Exams.QstCod = Tst_GetParamQstCod (); + + /***** Build anchor string *****/ + Frm_SetAnchorStr (Set.SetCod,&Anchor); + + /***** Show question and button to remove question *****/ + Ale_ShowAlertAndButton (ActRemExaQst,Anchor,NULL, + ExaSet_PutParamsOneQst,&Exams, + Btn_REMOVE_BUTTON,Txt_Remove_question, + Ale_QUESTION,Txt_Do_you_really_want_to_remove_the_question_X, + Exams.QstCod); + + /***** Free anchor string *****/ + Frm_FreeAnchorStr (Anchor); + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +/*****************************************************************************/ +/****************************** Remove a question ****************************/ +/*****************************************************************************/ + +void ExaSet_RemoveQstFromSet (void) + { + extern const char *Txt_Question_removed; + struct Exa_Exams Exams; + struct Exa_Exam Exam; + struct ExaSet_Set Set; + long QstCod; + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + Exa_ResetExam (&Exam); + ExaSet_ResetSet (&Set); + + /***** Get parameters *****/ + Exa_GetParams (&Exams); + if (Exams.ExaCod <= 0) + Lay_WrongExamExit (); + Set.ExaCod = Exam.ExaCod = Exams.ExaCod; + Set.SetCod = ExaSet_GetParamSetCod (); + if (Set.SetCod <= 0) + Lay_WrongSetExit (); + + /***** Get exam data from database *****/ + Exa_GetDataOfExamByCod (&Exam); + Exams.ExaCod = Exam.ExaCod; + if (!Exa_CheckIfEditable (&Exam)) + Lay_NoPermissionExit (); + + /***** Get set data from database *****/ + ExaSet_GetDataOfSetByCod (&Set); + Exams.SetCod = Set.SetCod; + + /***** Get question index *****/ + QstCod = Tst_GetParamQstCod (); + + /***** Remove the question from set *****/ + /* Remove the question itself */ + DB_QueryDELETE ("can not remove a question from a set", + "DELETE FROM exa_questions" + " WHERE SetCod=%ld AND QstCod=%ld", + Set.SetCod,QstCod); + if (!mysql_affected_rows (&Gbl.mysql)) + Lay_ShowErrorAndExit ("The question to be removed does not exist."); + + /***** Write message *****/ + Ale_ShowAlert (Ale_SUCCESS,Txt_Question_removed); + + /***** Show current exam and its sets *****/ + Exa_PutFormsOneExam (&Exams,&Exam,&Set, + false); // It's not a new exam + } + +/*****************************************************************************/ +/*********** Exchange the order of two consecutive sets in an exam ***********/ +/*****************************************************************************/ + +static void ExaSet_ExchangeSets (long ExaCod, + unsigned SetIndTop,unsigned SetIndBottom) + { + long SetCodTop; + long SetCodBottom; + + /***** Lock table to make the move atomic *****/ + DB_Query ("can not lock tables to exchange sets of questions", + "LOCK TABLES exa_sets WRITE"); + Gbl.DB.LockedTables = true; + + /***** Get set codes of the sets to be moved *****/ + SetCodTop = ExaSet_GetSetCodFromSetInd (ExaCod,SetIndTop); + SetCodBottom = ExaSet_GetSetCodFromSetInd (ExaCod,SetIndBottom); + + /***** Exchange indexes of sets *****/ + /* + Example: + SetIndTop = 1; SetCodTop = 218 + SetIndBottom = 2; SetCodBottom = 220 + Step 1 Step 2 Step 3 ++--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+ +| SetInd | SetCod | | SetInd | SetCod | | SetInd | SetCod | | SetInd | SetCod | ++--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+ +| 1 | 218 |>| -2 | 218 |>| -2 | 218 |>| 2 | 218 | +| 2 | 220 | | 2 | 220 | | 1 | 220 | | 1 | 220 | +| 3 | 232 | | 3 | 232 | | 3 | 232 | | 3 | 232 | ++--------+--------+ +--------+--------+ +--------+--------+ +--------+--------+ + */ + /* Step 1: change temporarily top index to minus bottom index + in order to not repeat unique index (ExaCod,SetInd) */ + DB_QueryUPDATE ("can not exchange indexes of sets", + "UPDATE exa_sets SET SetInd=-%u" + " WHERE ExaCod=%ld AND SetCod=%ld", + SetIndBottom, + ExaCod,SetCodTop); + + /* Step 2: change bottom index to old top index */ + DB_QueryUPDATE ("can not exchange indexes of sets", + "UPDATE exa_sets SET SetInd=%u" + " WHERE ExaCod=%ld AND SetCod=%ld", + SetIndTop, + ExaCod,SetCodBottom); + + /* Step 3: change top index to old bottom index */ + DB_QueryUPDATE ("can not exchange indexes of sets", + "UPDATE exa_sets SET SetInd=%u" + " WHERE ExaCod=%ld AND SetCod=%ld", + SetIndBottom, + ExaCod,SetCodTop); + + /***** Unlock table *****/ + Gbl.DB.LockedTables = false; // Set to false before the following unlock... + // ...to not retry the unlock if error in unlocking + DB_Query ("can not unlock tables after exchanging sets of questions", + "UNLOCK TABLES"); + } + +/*****************************************************************************/ +/***************** Put icon to add a new questions to exam *******************/ +/*****************************************************************************/ + +static void ExaSet_PutIconToAddNewQuestions (void *Exams) + { + extern const char *Txt_Add_questions; + + /***** Put form to create a new question *****/ + Ico_PutContextualIconToAdd (ActReqAddQstExaSet,NULL, + Exa_PutParams,Exams, + Txt_Add_questions); + } + +/*****************************************************************************/ +/***************** Put button to add new questions to exam *******************/ +/*****************************************************************************/ + +static void ExaSet_PutButtonToAddNewQuestions (struct Exa_Exams *Exams) + { + extern const char *Txt_Add_questions; + + Frm_StartForm (ActReqAddQstExaSet); + ExaSet_PutParamsOneSet (Exams); + Btn_PutConfirmButtonInline (Txt_Add_questions); + Frm_EndForm (); + } diff --git a/swad_exam_set.h b/swad_exam_set.h new file mode 100644 index 00000000..592d2811 --- /dev/null +++ b/swad_exam_set.h @@ -0,0 +1,75 @@ +// swad_exam_set.h: set of questions in exams + +#ifndef _SWAD_EXA_SET +#define _SWAD_EXA_SET +/* + SWAD (Shared Workspace At a Distance), + is a web platform developed at the University of Granada (Spain), + and used to support university teaching. + + This file is part of SWAD core. + Copyright (C) 1999-2020 Antonio Caņas Vargas + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General 3 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 "swad_date.h" +// #include "swad_exam_event.h" +#include "swad_exam_type.h" +// #include "swad_scope.h" + +/*****************************************************************************/ +/************************** Public types and constants ***********************/ +/*****************************************************************************/ + +/*****************************************************************************/ +/***************************** Public prototypes *****************************/ +/*****************************************************************************/ + +void ExaSet_PutParamsOneSet (void *Exams); +long ExaSet_GetParamSetCod (void); + +void ExaSet_ReceiveFormSet (void); +void ExaSet_ChangeSetTitle (void); +void ExaSet_ChangeNumQstsToExam (void); + +unsigned ExaSet_GetNumSetsExam (long ExaCod); +unsigned ExaSet_GetNumQstsExam (long ExaCod); + +void ExaSet_RequestCreatOrEditSet (void); +void ExaSet_ReqSelectQstsToAddToSet (void); +void ExaSet_ListQstsToAddToSet (void); + +void ExaSet_ListExamSets (struct Exa_Exams *Exams, + struct Exa_Exam *Exam, + struct ExaSet_Set *Set); + +void ExaSet_ResetSet (struct ExaSet_Set *Set); + +void ExaSet_AddQstsToSet (void); + +void ExaSet_RequestRemoveSet (void); +void ExaSet_RemoveSet (void); + +void ExaSet_MoveUpSet (void); +void ExaSet_MoveDownSet (void); + +void ExaSet_RequestRemoveQstFromSet (void); +void ExaSet_RemoveQstFromSet (void); + +#endif diff --git a/swad_test.c b/swad_test.c index 0322ea96..a1db9219 100644 --- a/swad_test.c +++ b/swad_test.c @@ -40,6 +40,7 @@ #include "swad_action.h" #include "swad_box.h" #include "swad_database.h" +#include "swad_exam_set.h" #include "swad_figure.h" #include "swad_form.h" #include "swad_global.h"