diff --git a/sql/swad.sql b/sql/swad.sql index e6909b149..0650d5161 100644 --- a/sql/swad.sql +++ b/sql/swad.sql @@ -533,6 +533,15 @@ CREATE TABLE IF NOT EXISTS exa_results ( Score DOUBLE PRECISION NOT NULL DEFAULT 0, UNIQUE INDEX(EvtCod,UsrCod)); -- +-- Table exa_sets: stores the question sets in the exams +-- +CREATE TABLE IF NOT EXISTS exa_sets ( + SetCod INT NOT NULL AUTO_INCREMENT, + ExaCod INT NOT NULL, + SetInd INT NOT NULL DEFAULT 0, + UNIQUE INDEX(SetCod), + INDEX(ExaCod,SetInd)); +-- -- Table exa_times: stores the elapsed time in every question in every exam event -- CREATE TABLE IF NOT EXISTS exa_times ( diff --git a/swad_action.c b/swad_action.c index 61d110bc8..b1f5ab8b1 100644 --- a/swad_action.c +++ b/swad_action.c @@ -717,9 +717,15 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] = [ActRemExa ] = {1882,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_RemoveExam ,NULL}, [ActHidExa ] = {1883,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_HideExam ,NULL}, [ActShoExa ] = {1884,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_UnhideExam ,NULL}, + [ActAddOneExaSet ] = {1892,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,Dat_SetIniEndDates ,Exa_RequestNewSet ,NULL}, + [ActReqRemExaSet ] = {1893,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_RequestRemoveSet ,NULL}, + [ActRemExaSet ] = {1894,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_RemoveSet ,NULL}, + [ActUp_ExaSet ] = {1895,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_MoveUpSet ,NULL}, + [ActDwnExaSet ] = {1896,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_MoveDownSet ,NULL}, + [ActAddOneExaQst ] = {1885,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,Dat_SetIniEndDates ,Exa_RequestNewQuestion ,NULL}, - [ActExaLstTstQst ] = {1886,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_ListTstQuestionsToSelect ,NULL}, - [ActAddTstQstToExa ] = {1887,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_AddTstQuestionsToExam ,NULL}, + [ActLstTstQstForExa ] = {1886,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_ListQuestionsToSelect ,NULL}, + [ActAddQstToExa ] = {1887,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_AddQuestionsToExam ,NULL}, [ActReqRemExaQst ] = {1888,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_RequestRemoveQst ,NULL}, [ActRemExaQst ] = {1889,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_RemoveQst ,NULL}, [ActUp_ExaQst ] = {1890,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,Exa_MoveUpQst ,NULL}, @@ -3688,12 +3694,17 @@ Act_Action_t Act_FromActCodToAction[1 + Act_MAX_ACTION_COD] = // Do not reuse un ActHidExa, // #1883 ActShoExa, // #1884 ActAddOneExaQst, // #1885 - ActExaLstTstQst, // #1886 - ActAddTstQstToExa, // #1887 + ActLstTstQstForExa, // #1886 + ActAddQstToExa, // #1887 ActReqRemExaQst, // #1888 ActRemExaQst, // #1889 ActUp_ExaQst, // #1890 ActDwnExaQst, // #1891 + ActAddOneExaSet, // #1892 + ActReqRemExaSet, // #1893 + ActRemExaSet, // #1894 + ActUp_ExaSet, // #1895 + ActDwnExaSet, // #1896 }; /*****************************************************************************/ diff --git a/swad_action.h b/swad_action.h index 04ad08184..257cfce70 100644 --- a/swad_action.h +++ b/swad_action.h @@ -64,7 +64,7 @@ typedef enum typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to indicate obsolete action -#define Act_MAX_ACTION_COD 1891 +#define Act_MAX_ACTION_COD 1896 #define Act_MAX_OPTIONS_IN_MENU_PER_TAB 13 @@ -683,89 +683,95 @@ typedef signed int Act_Action_t; // Must be a signed type, because -1 is used to #define ActRemExa (ActChgCrsTT1stDay + 156) #define ActHidExa (ActChgCrsTT1stDay + 157) #define ActShoExa (ActChgCrsTT1stDay + 158) -#define ActAddOneExaQst (ActChgCrsTT1stDay + 159) -#define ActExaLstTstQst (ActChgCrsTT1stDay + 160) -#define ActAddTstQstToExa (ActChgCrsTT1stDay + 161) -#define ActReqRemExaQst (ActChgCrsTT1stDay + 162) -#define ActRemExaQst (ActChgCrsTT1stDay + 163) -#define ActUp_ExaQst (ActChgCrsTT1stDay + 164) -#define ActDwnExaQst (ActChgCrsTT1stDay + 165) +#define ActAddOneExaSet (ActChgCrsTT1stDay + 159) +#define ActReqRemExaSet (ActChgCrsTT1stDay + 160) +#define ActRemExaSet (ActChgCrsTT1stDay + 161) +#define ActUp_ExaSet (ActChgCrsTT1stDay + 162) +#define ActDwnExaSet (ActChgCrsTT1stDay + 163) -#define ActSeeGam (ActChgCrsTT1stDay + 166) -#define ActReqRemMch (ActChgCrsTT1stDay + 167) -#define ActRemMch (ActChgCrsTT1stDay + 168) -#define ActReqNewMch (ActChgCrsTT1stDay + 169) -#define ActNewMch (ActChgCrsTT1stDay + 170) -#define ActResMch (ActChgCrsTT1stDay + 171) -#define ActBckMch (ActChgCrsTT1stDay + 172) -#define ActPlyPauMch (ActChgCrsTT1stDay + 173) -#define ActFwdMch (ActChgCrsTT1stDay + 174) -#define ActChgNumColMch (ActChgCrsTT1stDay + 175) -#define ActChgVisResMchQst (ActChgCrsTT1stDay + 176) -#define ActMchCntDwn (ActChgCrsTT1stDay + 177) -#define ActRefMchTch (ActChgCrsTT1stDay + 178) +#define ActAddOneExaQst (ActChgCrsTT1stDay + 164) +#define ActLstTstQstForExa (ActChgCrsTT1stDay + 165) +#define ActAddQstToExa (ActChgCrsTT1stDay + 166) +#define ActReqRemExaQst (ActChgCrsTT1stDay + 167) +#define ActRemExaQst (ActChgCrsTT1stDay + 168) +#define ActUp_ExaQst (ActChgCrsTT1stDay + 169) +#define ActDwnExaQst (ActChgCrsTT1stDay + 170) -#define ActJoiMch (ActChgCrsTT1stDay + 179) -#define ActSeeMchAnsQstStd (ActChgCrsTT1stDay + 180) -#define ActRemMchAnsQstStd (ActChgCrsTT1stDay + 181) -#define ActAnsMchQstStd (ActChgCrsTT1stDay + 182) -#define ActRefMchStd (ActChgCrsTT1stDay + 183) +#define ActSeeGam (ActChgCrsTT1stDay + 171) +#define ActReqRemMch (ActChgCrsTT1stDay + 172) +#define ActRemMch (ActChgCrsTT1stDay + 173) +#define ActReqNewMch (ActChgCrsTT1stDay + 174) +#define ActNewMch (ActChgCrsTT1stDay + 175) +#define ActResMch (ActChgCrsTT1stDay + 176) +#define ActBckMch (ActChgCrsTT1stDay + 177) +#define ActPlyPauMch (ActChgCrsTT1stDay + 178) +#define ActFwdMch (ActChgCrsTT1stDay + 179) +#define ActChgNumColMch (ActChgCrsTT1stDay + 180) +#define ActChgVisResMchQst (ActChgCrsTT1stDay + 181) +#define ActMchCntDwn (ActChgCrsTT1stDay + 182) +#define ActRefMchTch (ActChgCrsTT1stDay + 183) -#define ActSeeMyMchResCrs (ActChgCrsTT1stDay + 184) -#define ActSeeMyMchResGam (ActChgCrsTT1stDay + 185) -#define ActSeeMyMchResMch (ActChgCrsTT1stDay + 186) -#define ActSeeOneMchResMe (ActChgCrsTT1stDay + 187) +#define ActJoiMch (ActChgCrsTT1stDay + 184) +#define ActSeeMchAnsQstStd (ActChgCrsTT1stDay + 185) +#define ActRemMchAnsQstStd (ActChgCrsTT1stDay + 186) +#define ActAnsMchQstStd (ActChgCrsTT1stDay + 187) +#define ActRefMchStd (ActChgCrsTT1stDay + 188) -#define ActReqSeeAllMchRes (ActChgCrsTT1stDay + 188) -#define ActSeeAllMchResCrs (ActChgCrsTT1stDay + 189) -#define ActSeeAllMchResGam (ActChgCrsTT1stDay + 190) -#define ActSeeAllMchResMch (ActChgCrsTT1stDay + 191) -#define ActSeeOneMchResOth (ActChgCrsTT1stDay + 192) +#define ActSeeMyMchResCrs (ActChgCrsTT1stDay + 189) +#define ActSeeMyMchResGam (ActChgCrsTT1stDay + 190) +#define ActSeeMyMchResMch (ActChgCrsTT1stDay + 191) +#define ActSeeOneMchResMe (ActChgCrsTT1stDay + 192) -#define ActChgVisResMchUsr (ActChgCrsTT1stDay + 193) +#define ActReqSeeAllMchRes (ActChgCrsTT1stDay + 193) +#define ActSeeAllMchResCrs (ActChgCrsTT1stDay + 194) +#define ActSeeAllMchResGam (ActChgCrsTT1stDay + 195) +#define ActSeeAllMchResMch (ActChgCrsTT1stDay + 196) +#define ActSeeOneMchResOth (ActChgCrsTT1stDay + 197) -#define ActFrmNewGam (ActChgCrsTT1stDay + 194) -#define ActEdiOneGam (ActChgCrsTT1stDay + 195) -#define ActNewGam (ActChgCrsTT1stDay + 196) -#define ActChgGam (ActChgCrsTT1stDay + 197) -#define ActReqRemGam (ActChgCrsTT1stDay + 198) -#define ActRemGam (ActChgCrsTT1stDay + 199) -#define ActHidGam (ActChgCrsTT1stDay + 200) -#define ActShoGam (ActChgCrsTT1stDay + 201) -#define ActAddOneGamQst (ActChgCrsTT1stDay + 202) -#define ActGamLstTstQst (ActChgCrsTT1stDay + 203) -#define ActAddTstQstToGam (ActChgCrsTT1stDay + 204) -#define ActReqRemGamQst (ActChgCrsTT1stDay + 205) -#define ActRemGamQst (ActChgCrsTT1stDay + 206) -#define ActUp_GamQst (ActChgCrsTT1stDay + 207) -#define ActDwnGamQst (ActChgCrsTT1stDay + 208) +#define ActChgVisResMchUsr (ActChgCrsTT1stDay + 198) -#define ActSeeSvy (ActChgCrsTT1stDay + 209) -#define ActAnsSvy (ActChgCrsTT1stDay + 210) -#define ActFrmNewSvy (ActChgCrsTT1stDay + 211) -#define ActEdiOneSvy (ActChgCrsTT1stDay + 212) -#define ActNewSvy (ActChgCrsTT1stDay + 213) -#define ActChgSvy (ActChgCrsTT1stDay + 214) -#define ActReqRemSvy (ActChgCrsTT1stDay + 215) -#define ActRemSvy (ActChgCrsTT1stDay + 216) -#define ActReqRstSvy (ActChgCrsTT1stDay + 217) -#define ActRstSvy (ActChgCrsTT1stDay + 218) -#define ActHidSvy (ActChgCrsTT1stDay + 219) -#define ActShoSvy (ActChgCrsTT1stDay + 220) -#define ActEdiOneSvyQst (ActChgCrsTT1stDay + 221) -#define ActRcvSvyQst (ActChgCrsTT1stDay + 222) -#define ActReqRemSvyQst (ActChgCrsTT1stDay + 223) -#define ActRemSvyQst (ActChgCrsTT1stDay + 224) +#define ActFrmNewGam (ActChgCrsTT1stDay + 199) +#define ActEdiOneGam (ActChgCrsTT1stDay + 200) +#define ActNewGam (ActChgCrsTT1stDay + 201) +#define ActChgGam (ActChgCrsTT1stDay + 202) +#define ActReqRemGam (ActChgCrsTT1stDay + 203) +#define ActRemGam (ActChgCrsTT1stDay + 204) +#define ActHidGam (ActChgCrsTT1stDay + 205) +#define ActShoGam (ActChgCrsTT1stDay + 206) +#define ActAddOneGamQst (ActChgCrsTT1stDay + 207) +#define ActGamLstTstQst (ActChgCrsTT1stDay + 208) +#define ActAddTstQstToGam (ActChgCrsTT1stDay + 209) +#define ActReqRemGamQst (ActChgCrsTT1stDay + 210) +#define ActRemGamQst (ActChgCrsTT1stDay + 211) +#define ActUp_GamQst (ActChgCrsTT1stDay + 212) +#define ActDwnGamQst (ActChgCrsTT1stDay + 213) -#define ActSeeOneExaAnn (ActChgCrsTT1stDay + 225) -#define ActSeeDatExaAnn (ActChgCrsTT1stDay + 226) -#define ActEdiExaAnn (ActChgCrsTT1stDay + 227) -#define ActRcvExaAnn (ActChgCrsTT1stDay + 228) -#define ActPrnExaAnn (ActChgCrsTT1stDay + 229) -#define ActReqRemExaAnn (ActChgCrsTT1stDay + 230) -#define ActRemExaAnn (ActChgCrsTT1stDay + 231) -#define ActHidExaAnn (ActChgCrsTT1stDay + 232) -#define ActShoExaAnn (ActChgCrsTT1stDay + 233) +#define ActSeeSvy (ActChgCrsTT1stDay + 214) +#define ActAnsSvy (ActChgCrsTT1stDay + 215) +#define ActFrmNewSvy (ActChgCrsTT1stDay + 216) +#define ActEdiOneSvy (ActChgCrsTT1stDay + 217) +#define ActNewSvy (ActChgCrsTT1stDay + 218) +#define ActChgSvy (ActChgCrsTT1stDay + 219) +#define ActReqRemSvy (ActChgCrsTT1stDay + 220) +#define ActRemSvy (ActChgCrsTT1stDay + 221) +#define ActReqRstSvy (ActChgCrsTT1stDay + 222) +#define ActRstSvy (ActChgCrsTT1stDay + 223) +#define ActHidSvy (ActChgCrsTT1stDay + 224) +#define ActShoSvy (ActChgCrsTT1stDay + 225) +#define ActEdiOneSvyQst (ActChgCrsTT1stDay + 226) +#define ActRcvSvyQst (ActChgCrsTT1stDay + 227) +#define ActReqRemSvyQst (ActChgCrsTT1stDay + 228) +#define ActRemSvyQst (ActChgCrsTT1stDay + 229) + +#define ActSeeOneExaAnn (ActChgCrsTT1stDay + 230) +#define ActSeeDatExaAnn (ActChgCrsTT1stDay + 231) +#define ActEdiExaAnn (ActChgCrsTT1stDay + 232) +#define ActRcvExaAnn (ActChgCrsTT1stDay + 233) +#define ActPrnExaAnn (ActChgCrsTT1stDay + 234) +#define ActReqRemExaAnn (ActChgCrsTT1stDay + 235) +#define ActRemExaAnn (ActChgCrsTT1stDay + 236) +#define ActHidExaAnn (ActChgCrsTT1stDay + 237) +#define ActShoExaAnn (ActChgCrsTT1stDay + 238) /*****************************************************************************/ /******************************** Files tab **********************************/ diff --git a/swad_changelog.h b/swad_changelog.h index a70851cc0..7e31c154a 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -544,10 +544,14 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - * En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 19.193.5 (2020-04-23)" +#define Log_PLATFORM_VERSION "SWAD 19.194 (2020-04-24)" #define CSS_FILE "swad19.193.1.css" #define JS_FILE "swad19.193.1.js" /* + Version 19.194: Apr 24, 2020 New database table for question sets in exams. (298257 lines) + 1 change necessary in database: +CREATE TABLE IF NOT EXISTS exa_sets (SetCod INT NOT NULL AUTO_INCREMENT,ExaCod INT NOT NULL,SetInd INT NOT NULL DEFAULT 0,UNIQUE INDEX(SetCod),INDEX(ExaCod,SetInd)); + Version 19.193.5: Apr 23, 2020 Fixed bug in exam events. (297871 lines) Version 19.193.4: Apr 23, 2020 Fixed bugs in exams, exam events, games and matches. (297860 lines) Version 19.193.3: Apr 23, 2020 Added new MIME type, reported by Jesús Garrido Manrique. diff --git a/swad_database.c b/swad_database.c index 8f4068300..e425b03ef 100644 --- a/swad_database.c +++ b/swad_database.c @@ -1182,6 +1182,25 @@ mysql> DESCRIBE exa_results; "Score DOUBLE PRECISION NOT NULL DEFAULT 0," "UNIQUE INDEX(EvtCod,UsrCod))"); + /***** Table exa_sets *****/ +/* +mysql> DESCRIBE exa_sets; ++--------+---------+------+-----+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++--------+---------+------+-----+---------+-------+ +| ExaCod | int(11) | NO | MUL | NULL | | +| QstCod | int(11) | NO | MUL | NULL | | +| QstInd | int(11) | NO | | 0 | | ++--------+---------+------+-----+---------+-------+ +3 rows in set (0.01 sec) +*/ + DB_CreateTable ("CREATE TABLE IF NOT EXISTS exa_sets (" + "SetCod INT NOT NULL AUTO_INCREMENT," + "ExaCod INT NOT NULL," + "SetInd INT NOT NULL DEFAULT 0," + "UNIQUE INDEX(SetCod)," + "INDEX(ExaCod,SetInd))"); + /***** Table exa_times *****/ /* mysql> DESCRIBE exa_times; diff --git a/swad_exam.c b/swad_exam.c index 96fa39460..cefeaf977 100644 --- a/swad_exam.c +++ b/swad_exam.c @@ -130,6 +130,7 @@ static void Exa_PutFormsToRemEditOneExam (struct Exa_Exams *Exams, const struct Exa_Exam *Exam, const char *Anchor); +static void Exa_PutParamsOneSet (void *Exams); static void Exa_PutParamsOneQst (void *Exams); static void Exa_PutHiddenParamOrder (Exa_Order_t SelectedOrder); static Exa_Order_t Exa_GetParamOrder (void); @@ -153,15 +154,26 @@ static void Exa_UpdateExam (struct Exa_Exam *Exam,const char *Txt); static void Exa_RemAnswersOfAQuestion (long ExaCod,unsigned QstInd); +static unsigned Exa_GetMaxSetIndexInExam (long ExaCod); static unsigned Exa_GetMaxQuestionIndexInExam (long ExaCod); +static void Exa_ListExamSets (struct Exa_Exams *Exams,struct Exa_Exam *Exam); static void Exa_ListExamQuestions (struct Exa_Exams *Exams,struct Exa_Exam *Exam); +static void Exa_ListOneOrMoreSetsForEdition (struct Exa_Exams *Exams, + long ExaCod,unsigned NumSets, + MYSQL_RES *mysql_res, + bool ICanEditSets); +static void Exa_SetConstructor (struct Exa_Set *Set); +static void Exa_SetDestructor (struct Exa_Set *Set); +static void Exa_PutParamSetCod (void *SetCod); static void Exa_ListOneOrMoreQuestionsForEdition (struct Exa_Exams *Exams, long ExaCod,unsigned NumQsts, MYSQL_RES *mysql_res, bool ICanEditQuestions); static void Exa_ListQuestionForEdition (const struct Tst_Question *Question, unsigned QstInd,bool QuestionExists); +static void Exa_PutIconToAddNewSets (void *Exams); static void Exa_PutIconToAddNewQuestions (void *Exams); +static void Exa_PutButtonToAddNewSet (struct Exa_Exams *Exams); static void Exa_PutButtonToAddNewQuestions (struct Exa_Exams *Exams); static void Exa_AllocateListSelectedQuestions (struct Exa_Exams *Exams); @@ -189,6 +201,7 @@ void Exa_ResetExams (struct Exa_Exams *Exams) Exams->ExaCodsSelected = NULL; // String with selected exam codes separated by separator multiple Exams->ExaCod = -1L; // Selected/current exam code Exams->EvtCod = -1L; // Selected/current event code + Exams->SetInd = 0; // Current set index Exams->QstInd = 0; // Current question index } @@ -736,6 +749,19 @@ static void Exa_PutFormsToRemEditOneExam (struct Exa_Exams *Exams, Exa_PutParams,Exams); } +/*****************************************************************************/ +/************** Put parameter to move/remove one question set ****************/ +/*****************************************************************************/ + +static void Exa_PutParamsOneSet (void *Exams) + { + if (Exams) + { + Exa_PutParams (Exams); + Exa_PutParamSetInd (((struct Exa_Exams *) Exams)->SetInd); + } + } + /*****************************************************************************/ /**************** Put parameter to move/remove one question ******************/ /*****************************************************************************/ @@ -1369,9 +1395,13 @@ void Exa_RequestCreatOrEditExam (void) /* Show exams again */ Exa_ListAllExams (&Exams); else + { + /* Show sets of the exam ready to be edited */ + Exa_ListExamSets (&Exams,&Exam); + /* Show questions of the exam ready to be edited */ Exa_ListExamQuestions (&Exams,&Exam); - + } } /*****************************************************************************/ @@ -1663,6 +1693,42 @@ unsigned Exa_GetNumQstsExam (long ExaCod) ExaCod); } +/*****************************************************************************/ +/************* Put a form to edit/create a question set in exam **************/ +/*****************************************************************************/ + +void Exa_RequestNewSet (void) + { + struct Exa_Exams Exams; + struct Exa_Exam Exam; + + /***** Reset exams context *****/ + Exa_ResetExams (&Exams); + + /***** Reset exam *****/ + Exa_ResetExam (&Exam); + + /***** Get parameters *****/ + if ((Exam.ExaCod = Exa_GetParams (&Exams)) <= 0) + Lay_ShowErrorAndExit ("Code of exam is missing."); + Exa_GetDataOfExamByCod (&Exam); + + /***** Check if exam has events *****/ + if (Exa_CheckIfEditable (&Exam)) + { + /***** Show form to create a new question in this exam *****/ + Exams.ExaCod = Exam.ExaCod; + Tst_RequestSelectTestsForExam (&Exams); + } + else + Lay_NoPermissionExit (); + + /***** Show current exam *****/ + Exa_ShowOnlyOneExam (&Exams,&Exam, + true, // List exam questions + false); // Do not put form to start new event + } + /*****************************************************************************/ /*************** Put a form to edit/create a question in exam ****************/ /*****************************************************************************/ @@ -1703,7 +1769,7 @@ void Exa_RequestNewQuestion (void) /**************** List several test questions for selection ******************/ /*****************************************************************************/ -void Exa_ListTstQuestionsToSelect (void) +void Exa_ListQuestionsToSelect (void) { struct Exa_Exams Exams; struct Exa_Exam Exam; @@ -1730,6 +1796,15 @@ void Exa_ListTstQuestionsToSelect (void) Lay_NoPermissionExit (); } +/*****************************************************************************/ +/**************** Write parameter with index of question set *****************/ +/*****************************************************************************/ + +void Exa_PutParamSetInd (unsigned SetInd) + { + Par_PutHiddenParamUnsigned (NULL,"SetInd",SetInd); + } + /*****************************************************************************/ /****************** Write parameter with index of question *******************/ /*****************************************************************************/ @@ -1798,6 +1873,35 @@ 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 Exa_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 maximum question index in an exam *********************/ /*****************************************************************************/ @@ -1811,7 +1915,7 @@ static unsigned Exa_GetMaxQuestionIndexInExam (long ExaCod) unsigned QstInd = 0; /***** Get maximum question index in an exam from database *****/ - DB_QuerySELECT (&mysql_res,"can not get last question index", + DB_QuerySELECT (&mysql_res,"can not get max question index", "SELECT MAX(QstInd)" " FROM exa_questions" " WHERE ExaCod=%ld", @@ -1819,7 +1923,7 @@ static unsigned Exa_GetMaxQuestionIndexInExam (long ExaCod) row = mysql_fetch_row (mysql_res); if (row[0]) // There are questions if (sscanf (row[0],"%u",&QstInd) != 1) - Lay_ShowErrorAndExit ("Error when getting last question index."); + Lay_ShowErrorAndExit ("Error when getting max question index."); /***** Free structure that stores the query result *****/ DB_FreeMySQLResult (&mysql_res); @@ -1895,6 +1999,59 @@ unsigned Exa_GetNextQuestionIndexInExam (long ExaCod,unsigned QstInd) return NextQstInd; } +/*****************************************************************************/ +/************************* List the sets of an exam **************************/ +/*****************************************************************************/ + +static void Exa_ListExamSets (struct Exa_Exams *Exams,struct Exa_Exam *Exam) + { + extern const char *Hlp_ASSESSMENT_Exams_question_sets; + extern const char *Txt_Question_sets; + extern const char *Txt_This_exam_has_no_question_sets; + MYSQL_RES *mysql_res; + unsigned NumSets; + bool ICanEditSets = Exa_CheckIfEditable (Exam); + + /***** Get data of question sets from database *****/ + NumSets = (unsigned) + DB_QuerySELECT (&mysql_res,"can not get exam question sets", + "SELECT SetInd," // row[0] + "SetCod" // row[1] + " FROM exa_sets" + " WHERE ExaCod=%ld" + " ORDER BY SetInd", + Exam->ExaCod); + + /***** Begin box *****/ + Exams->ExaCod = Exam->ExaCod; + if (ICanEditSets) + Box_BoxBegin (NULL,Txt_Question_sets, + Exa_PutIconToAddNewSets,Exams, + Hlp_ASSESSMENT_Exams_question_sets,Box_NOT_CLOSABLE); + else + Box_BoxBegin (NULL,Txt_Question_sets, + NULL,NULL, + Hlp_ASSESSMENT_Exams_question_sets,Box_NOT_CLOSABLE); + + /***** Show table with sets *****/ + if (NumSets) + Exa_ListOneOrMoreSetsForEdition (Exams, + Exam->ExaCod,NumSets,mysql_res, + ICanEditSets); + else // This exam has no sets + Ale_ShowAlert (Ale_INFO,Txt_This_exam_has_no_question_sets); + + /***** Put button to add a new set in this exam *****/ + if (ICanEditSets) // I can edit question sets + Exa_PutButtonToAddNewSet (Exams); + + /***** Free structure that stores the query result *****/ + DB_FreeMySQLResult (&mysql_res); + + /***** End box *****/ + Box_BoxEnd (); + } + /*****************************************************************************/ /************************ List the questions of an exam ***********************/ /*****************************************************************************/ @@ -1948,6 +2105,170 @@ static void Exa_ListExamQuestions (struct Exa_Exams *Exams,struct Exa_Exam *Exam Box_BoxEnd (); } +/*****************************************************************************/ +/************************* List exam sets for edition ************************/ +/*****************************************************************************/ + +static void Exa_ListOneOrMoreSetsForEdition (struct Exa_Exams *Exams, + long ExaCod,unsigned NumSets, + MYSQL_RES *mysql_res, + bool ICanEditSets) + { + extern const char *Txt_Question_sets; + extern const char *Txt_No_INDEX; + extern const char *Txt_Code; + extern const char *Txt_Tags; + extern const char *Txt_Question_set; + extern const char *Txt_Move_up_X; + extern const char *Txt_Move_down_X; + extern const char *Txt_Movement_not_allowed; + unsigned NumSet; + MYSQL_ROW row; + struct Exa_Set Set; + unsigned SetInd; + unsigned MaxSetInd; + char StrSetInd[Cns_MAX_DECIMAL_DIGITS_UINT + 1]; + // bool SetExists; + + /***** Get maximum question index *****/ + MaxSetInd = Exa_GetMaxSetIndexInExam (ExaCod); + + /***** 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_set); + + HTM_TR_End (); + + /***** Write rows *****/ + for (NumSet = 0; + NumSet < NumSets; + NumSet++) + { + Gbl.RowEvenOdd = NumSet % 2; + + /***** Create question set *****/ + Exa_SetConstructor (&Set); + + /***** Get set data *****/ + row = mysql_fetch_row (mysql_res); + /* + row[0] SetInd + row[1] SetCod + */ + + /* Get set index (row[0]) */ + SetInd = Str_ConvertStrToUnsigned (row[0]); + snprintf (StrSetInd,sizeof (SetInd), + "%u", + SetInd); + + /* Get set code (row[1]) */ + Set.SetCod = Str_ConvertStrCodToLongCod (row[1]); + + /***** Icons *****/ + Exams->ExaCod = ExaCod; + Exams->SetInd = SetInd; + HTM_TR_Begin (NULL); + + HTM_TD_Begin ("class=\"BT%u\"",Gbl.RowEvenOdd); + + /* Put icon to remove the set */ + if (ICanEditSets) + { + Frm_StartForm (ActReqRemExaSet); + Exa_PutParams (Exams); + Exa_PutParamQstInd (SetInd); + Ico_PutIconRemove (); + Frm_EndForm (); + } + else + Ico_PutIconRemovalNotAllowed (); + + /* Put icon to move up the question */ + if (ICanEditSets && SetInd > 1) + { + Lay_PutContextualLinkOnlyIcon (ActUp_ExaSet,NULL, + Exa_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 && SetInd < MaxSetInd) + { + Lay_PutContextualLinkOnlyIcon (ActDwnExaSet,NULL, + Exa_PutParamsOneSet,Exams, + "arrow-down.svg", + Str_BuildStringStr (Txt_Move_down_X, + StrSetInd)); + Str_FreeString (); + } + else + Ico_PutIconOff ("arrow-down.svg",Txt_Movement_not_allowed); + + /* Put icon to edit the set */ + if (ICanEditSets) + // Ico_PutContextualIconToEdit (ActEdiOneExaSet,NULL, + // Exa_PutParamSetCod,&Set.SetCod); + Ico_PutContextualIconToEdit (ActEdiOneTstQst,NULL, // TODO: Change for ActEdiOneExaSet + Exa_PutParamSetCod,&Set.SetCod); + + HTM_TD_End (); + + /***** Set *****/ + // SetExists = Exa_GetSetDataFromDB (&Set); + // Exa_ListSetForEdition (&Set,SetInd,SetExists); + + HTM_TR_End (); + + /***** Destroy question set *****/ + Exa_SetDestructor (&Set); + } + + /***** End table *****/ + HTM_TABLE_End (); + } + +/*****************************************************************************/ +/************************** Question set constructor *************************/ +/*****************************************************************************/ + +static void Exa_SetConstructor (struct Exa_Set *Set) + { + Set->SetCod = -1L; + } + +/*****************************************************************************/ +/*************************** Question set destructor *************************/ +/*****************************************************************************/ + +static void Exa_SetDestructor (struct Exa_Set *Set) + { + Set->SetCod = -1L; // TODO: Remove + } + +/*****************************************************************************/ +/*************** Put parameter with set code to edit, remove... **************/ +/*****************************************************************************/ + +static void Exa_PutParamSetCod (void *SetCod) // Should be a pointer to long + { + if (SetCod) + if (*((long *) SetCod) > 0) // If set exists + Par_PutHiddenParamLong (NULL,"SetCod",*((long *) SetCod)); + } + /*****************************************************************************/ /********************* List exam questions for edition ***********************/ /*****************************************************************************/ @@ -2136,6 +2457,20 @@ static void Exa_ListQuestionForEdition (const struct Tst_Question *Question, HTM_TD_End (); } +/*****************************************************************************/ +/*************** Put icon to add a new question set to exam ******************/ +/*****************************************************************************/ + +static void Exa_PutIconToAddNewSets (void *Exams) + { + extern const char *Txt_Add_question_set; + + /***** Put form to create a new question set *****/ + Ico_PutContextualIconToAdd (ActAddOneExaSet,NULL, + Exa_PutParams,Exams, + Txt_Add_question_set); + } + /*****************************************************************************/ /***************** Put icon to add a new questions to exam *******************/ /*****************************************************************************/ @@ -2150,6 +2485,20 @@ static void Exa_PutIconToAddNewQuestions (void *Exams) Txt_Add_questions); } +/*****************************************************************************/ +/*************** Put button to add new question set to exam ******************/ +/*****************************************************************************/ + +static void Exa_PutButtonToAddNewSet (struct Exa_Exams *Exams) + { + extern const char *Txt_Add_question_set; + + Frm_StartForm (ActAddOneExaSet); + Exa_PutParams (Exams); + Btn_PutConfirmButton (Txt_Add_question_set); + Frm_EndForm (); + } + /*****************************************************************************/ /***************** Put button to add new questions to exam *******************/ /*****************************************************************************/ @@ -2168,7 +2517,7 @@ static void Exa_PutButtonToAddNewQuestions (struct Exa_Exams *Exams) /******************** Add selected test questions to exam ********************/ /*****************************************************************************/ -void Exa_AddTstQuestionsToExam (void) +void Exa_AddQuestionsToExam (void) { extern const char *Txt_No_questions_have_been_added; struct Exa_Exams Exams; @@ -2289,6 +2638,39 @@ static unsigned Exa_CountNumQuestionsInList (const struct Exa_Exams *Exams) return NumQuestions; } +/*****************************************************************************/ +/******************* Request the removal of a question set *******************/ +/*****************************************************************************/ + +void Exa_RequestRemoveSet (void) + { + } + +/*****************************************************************************/ +/*************************** Remove a question set ***************************/ +/*****************************************************************************/ + +void Exa_RemoveSet (void) + { + } + + +/*****************************************************************************/ +/************** Move up position of a question set in an exam ****************/ +/*****************************************************************************/ + +void Exa_MoveUpSet (void) + { + } + +/*****************************************************************************/ +/************* Move down position of a question set in an exam ***************/ +/*****************************************************************************/ + +void Exa_MoveDownSet (void) + { + } + /*****************************************************************************/ /********************** Request the removal of a question ********************/ /*****************************************************************************/ diff --git a/swad_exam.h b/swad_exam.h index ce9763a72..f345a46b7 100644 --- a/swad_exam.h +++ b/swad_exam.h @@ -74,6 +74,7 @@ struct Exa_Exams char *ExaCodsSelected; // String with selected exam codes separated by separator multiple long ExaCod; // Selected/current exam code long EvtCod; // Selected/current match code + unsigned SetInd; // Current set index unsigned QstInd; // Current question index }; @@ -94,6 +95,11 @@ struct Exa_Exam unsigned NumUnfinishedEvts; // Number of unfinished events in the exam }; +struct Exa_Set + { + long SetCod; + }; + /*****************************************************************************/ /***************************** Public prototypes *****************************/ /*****************************************************************************/ @@ -139,16 +145,25 @@ bool Mch_CheckIfMatchIsAssociatedToGrp (long EvtCod,long GrpCod); unsigned Exa_GetNumQstsExam (long ExaCod); -void Exa_RequestNewQuestion (void); -void Exa_ListTstQuestionsToSelect (void); +void Exa_RequestNewSet (void); +void Exa_RequestNewQuestion (void); +void Exa_ListQuestionsToSelect (void); + +void Exa_PutParamSetInd (unsigned SetInd); void Exa_PutParamQstInd (unsigned QstInd); unsigned Exa_GetParamQstInd (void); long Exa_GetQstCodFromQstInd (long ExaCod,unsigned QstInd); unsigned Exa_GetPrevQuestionIndexInExam (long ExaCod,unsigned QstInd); unsigned Exa_GetNextQuestionIndexInExam (long ExaCod,unsigned QstInd); -void Exa_AddTstQuestionsToExam (void); +void Exa_AddQuestionsToExam (void); + +void Exa_RequestRemoveSet (void); +void Exa_RemoveSet (void); + +void Exa_MoveUpSet (void); +void Exa_MoveDownSet (void); void Exa_RequestRemoveQst (void); void Exa_RemoveQst (void); diff --git a/swad_help_URL.c b/swad_help_URL.c index 0841fc591..0074833bd 100644 --- a/swad_help_URL.c +++ b/swad_help_URL.c @@ -1453,6 +1453,27 @@ const char *Hlp_ASSESSMENT_Exams_edit_exam = "ASSESSMENT.Exams.en#edit-exam"; #endif +const char *Hlp_ASSESSMENT_Exams_question_sets = +#if L==1 + "ASSESSMENT.Exams.es#conjunto-de-preguntas"; +#elif L==2 + "ASSESSMENT.Exams.en#question-set"; +#elif L==3 + "ASSESSMENT.Exams.en#question-set"; +#elif L==4 + "ASSESSMENT.Exams.es#conjunto-de-preguntas"; +#elif L==5 + "ASSESSMENT.Exams.en#question-set"; +#elif L==6 + "ASSESSMENT.Exams.es#conjunto-de-preguntas"; +#elif L==7 + "ASSESSMENT.Exams.en#question-set"; +#elif L==8 + "ASSESSMENT.Exams.en#question-set"; +#elif L==9 + "ASSESSMENT.Exams.en#question-set"; +#endif + const char *Hlp_ASSESSMENT_Exams_events = #if L==1 "ASSESSMENT.Exams.es#eventos"; diff --git a/swad_test.c b/swad_test.c index 975a508bc..79ed6d38a 100644 --- a/swad_test.c +++ b/swad_test.c @@ -1278,7 +1278,7 @@ static void Tst_ShowFormRequestSelectTestsForExam (struct Exa_Exams *Exams, /***** Get tags already present in the table of questions *****/ if ((Test->Tags.Num = Tst_GetAllTagsFromCurrentCrs (&mysql_res))) { - Frm_StartForm (ActExaLstTstQst); + Frm_StartForm (ActLstTstQstForExa); Exa_PutParams (Exams); HTM_TABLE_BeginPadding (2); @@ -2995,7 +2995,7 @@ static void Tst_ListOneOrMoreQuestionsForSelectionForExam (struct Exa_Exams *Exa Hlp_ASSESSMENT_Exams_questions,Box_NOT_CLOSABLE); /***** Begin form *****/ - Frm_StartForm (ActAddTstQstToExa); + Frm_StartForm (ActAddQstToExa); Exa_PutParams (Exams); /***** Write the heading *****/ @@ -5872,16 +5872,11 @@ static long Tst_GetQstCod (void) /************ Put parameter with question code to edit, remove... ************/ /*****************************************************************************/ -void Tst_PutParamQstCod (void *QstCodPtr) // Should be a pointer to long +void Tst_PutParamQstCod (void *QstCod) // Should be a pointer to long { - long QstCod; - - if (QstCodPtr) - { - QstCod = *((long *) QstCodPtr); - if (QstCod > 0) // If question exists - Par_PutHiddenParamLong (NULL,"QstCod",QstCod); - } + if (QstCod) + if (*((long *) QstCod) > 0) // If question exists + Par_PutHiddenParamLong (NULL,"QstCod",*((long *) QstCod)); } /*****************************************************************************/ diff --git a/swad_test.h b/swad_test.h index 20f773e65..dbac0c11f 100644 --- a/swad_test.h +++ b/swad_test.h @@ -217,7 +217,7 @@ void Tst_RemoveOneQst (void); void Tst_ChangeShuffleQst (void); -void Tst_PutParamQstCod (void *QstCodPtr); +void Tst_PutParamQstCod (void *QstCod); void Tst_InsertOrUpdateQstTagsAnsIntoDB (struct Tst_Question *Question);