diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 2768e53f..43923f23 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -11,7 +11,7 @@ - + diff --git a/swad_action.c b/swad_action.c index 50109584..f0b65cc8 100644 --- a/swad_action.c +++ b/swad_action.c @@ -728,9 +728,9 @@ const struct Act_Actions Act_Actions[Act_NUM_ACTIONS] = [ActHidExaSes ] = {1900,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,ExaSes_HideSession ,NULL}, [ActUnhExaSes ] = {1901,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,ExaSes_UnhideSession ,NULL}, - [ActSeeExaPrn ] = {1904,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,ExaPrn_ShowExamPrint ,NULL}, + [ActSeeExaPrn ] = {1904,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_NEW_TAB,NULL ,ExaPrn_ShowExamPrint ,NULL}, [ActAnsExaPrn ] = {1906,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_AJAX_NORMAL,NULL ,ExaPrn_ReceivePrintAnswer ,NULL}, - [ActEndExaPrn ] = {1908,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,ExaRes_ShowOneExaResult ,NULL}, + [ActEndExaPrn ] = {1908,-1,TabUnk,ActSeeAllExa ,0x238,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_2ND_TAB,NULL ,ExaRes_ShowOneExaResult ,NULL}, [ActSeeMyExaResCrs ] = {1867,-1,TabUnk,ActSeeAllExa ,0x208,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,ExaRes_ShowMyResultsInCrs ,NULL}, [ActSeeMyExaResExa ] = {1868,-1,TabUnk,ActSeeAllExa ,0x208,0x200, 0, 0, 0, 0, 0,Act_CONT_NORM,Act_BRW_1ST_TAB,NULL ,ExaRes_ShowMyResultsInExa ,NULL}, diff --git a/swad_changelog.h b/swad_changelog.h index 1483498e..4815bf6f 100644 --- a/swad_changelog.h +++ b/swad_changelog.h @@ -555,7 +555,7 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - * En OpenSWAD: ps2pdf source.ps destination.pdf */ -#define Log_PLATFORM_VERSION "SWAD 20.8 (2020-12-15)" +#define Log_PLATFORM_VERSION "SWAD 20.9 (2021-01-20)" #define CSS_FILE "swad20.8.css" #define JS_FILE "swad20.6.2.js" /* @@ -602,6 +602,8 @@ Juan Miguel. TODO: Fix bug: un profesor editor no puede ver las carpetas de TFG (proyectos) de otros. Debería poder. TODO: DNI de un estudiante sale erróneamente como ******* en lugar de mostrarse al ver los accesos de un estudiante a la asignatura. + Version 20.9: Jan 20, 2021 Exam print ready to be answered is displayed in a new tab. + Code refactoring in exam results. (304829 lines) Version 20.8: Dec 15, 2020 Fixed bug in file browser. Reported by Javier Fernández Baldomero. (304711 lines) Version 20.7.4: Dec 01, 2020 Fixed bug in pagination of forums of a thread. Reported by Javier Fernández Baldomero. (304705 lines) Version 20.7.3: Nov 26, 2020 Fixed bugs in pagination when editing assignments. (304706 lines) diff --git a/swad_exam_log.c b/swad_exam_log.c index fda1fd89..e7cf35fc 100644 --- a/swad_exam_log.c +++ b/swad_exam_log.c @@ -306,20 +306,6 @@ void ExaLog_ShowExamLog (const struct ExaPrn_Print *Print) char *UserAgent; const char *Class; - /***** Check if I can view this print result *****/ - switch (Gbl.Usrs.Me.Role.Logged) - { - case Rol_NET: - case Rol_TCH: - case Rol_DEG_ADM: - case Rol_CTR_ADM: - case Rol_INS_ADM: - case Rol_SYS_ADM: - break; - default: // Other users can not see log - return; - } - /***** Get print log from database *****/ NumClicks = (unsigned) DB_QuerySELECT (&mysql_res,"can not get exam print log", diff --git a/swad_exam_print.c b/swad_exam_print.c index 6e245e40..1fd7a0ef 100644 --- a/swad_exam_print.c +++ b/swad_exam_print.c @@ -43,6 +43,8 @@ #include "swad_exam_type.h" #include "swad_form.h" #include "swad_global.h" +#include "swad_ID.h" +#include "swad_photo.h" /*****************************************************************************/ /************** External global variables from others modules ****************/ @@ -80,7 +82,7 @@ static void ExaPrn_CreatePrintInDB (struct ExaPrn_Print *Print); static void ExaPrn_ShowExamPrintToFillIt (struct Exa_Exams *Exams, const struct Exa_Exam *Exam, - const struct ExaPrn_Print *Print); + struct ExaPrn_Print *Print); static void ExaPrn_GetAndWriteDescription (long ExaCod); static void ExaPrn_ShowTableWithQstsToFill (struct Exa_Exams *Exams, const struct ExaPrn_Print *Print); @@ -202,7 +204,7 @@ void ExaPrn_ShowExamPrint (void) /***** Get exam print data from database *****/ ExaPrn_GetDataOfPrintBySesCodAndUsrCod (&Print); - if (Print.PrnCod <= 0) // Print does not exists ==> create it + if (Print.PrnCod <= 0) // Exam print does not exists ==> create it { /***** Set again basic data of exam print *****/ Print.SesCod = Session.SesCod; @@ -222,7 +224,7 @@ void ExaPrn_ShowExamPrint (void) ExaLog_SetIfCanAnswer (true); } } - else // Print exists + else // Exam print exists { /***** Get exam print data from database *****/ ExaPrn_GetDataOfPrintBySesCodAndUsrCod (&Print); @@ -666,20 +668,34 @@ void ExaPrn_GetPrintQuestionsFromDB (struct ExaPrn_Print *Print) static void ExaPrn_ShowExamPrintToFillIt (struct Exa_Exams *Exams, const struct Exa_Exam *Exam, - const struct ExaPrn_Print *Print) + struct ExaPrn_Print *Print) { - extern const char *Hlp_ASSESSMENT_Exams; + extern const char *Hlp_ASSESSMENT_Exams_answer_exam; /***** Begin box *****/ Box_BoxBegin (NULL,Exam->Title, NULL,NULL, - Hlp_ASSESSMENT_Exams,Box_NOT_CLOSABLE); + Hlp_ASSESSMENT_Exams_answer_exam,Box_NOT_CLOSABLE); /***** Heading *****/ + /* Institution, degree and course */ Lay_WriteHeaderClassPhoto (false,false, Gbl.Hierarchy.Ins.InsCod, Gbl.Hierarchy.Deg.DegCod, Gbl.Hierarchy.Crs.CrsCod); + + + /***** Show user and time *****/ + /* Begin table */ + HTM_TABLE_BeginWideMarginPadding (10); + + /* User */ + ExaRes_ShowExamResultUser (&Gbl.Usrs.Me.UsrDat); + + /* End table */ + HTM_TABLE_End (); + + /* Exam description */ ExaPrn_GetAndWriteDescription (Exam->ExaCod); if (Print->NumQsts.All) diff --git a/swad_exam_result.c b/swad_exam_result.c index 45b5d591..1ae11daf 100644 --- a/swad_exam_result.c +++ b/swad_exam_result.c @@ -124,7 +124,16 @@ static void ExaRes_CheckIfICanSeePrintResult (const struct Exa_Exam *Exam, struct ExaRes_ICanView *ICanView); static void ExaRes_ComputeValidPrintScore (struct ExaPrn_Print *Print); - +static void ExaRes_ShowExamResultTime (struct ExaPrn_Print *Print); +static void ExaRes_ShowExamResultNumQsts (struct ExaPrn_Print *Print, + const struct ExaRes_ICanView *ICanView); +static void ExaRes_ShowExamResultNumAnss (struct ExaPrn_Print *Print, + const struct ExaRes_ICanView *ICanView); +static void ExaRes_ShowExamResultScore (struct ExaPrn_Print *Print, + const struct ExaRes_ICanView *ICanView); +static void ExaRes_ShowExamResultGrade (const struct Exa_Exam *Exam, + struct ExaPrn_Print *Print, + const struct ExaRes_ICanView *ICanView); static void ExaRes_ShowExamAnswers (struct UsrData *UsrDat, struct ExaPrn_Print *Print, unsigned Visibility); @@ -1371,7 +1380,19 @@ void ExaRes_ShowOneExaResult (void) ExaRes_ShowExamResult (&Exam,&Session,&Print,UsrDat); /***** Show exam log *****/ - ExaLog_ShowExamLog (&Print); + switch (Gbl.Usrs.Me.Role.Logged) + { + case Rol_NET: + case Rol_TCH: + case Rol_DEG_ADM: + case Rol_CTR_ADM: + case Rol_INS_ADM: + case Rol_SYS_ADM: + ExaLog_ShowExamLog (&Print); + break; + default: // Other users can not see log + return; + } } /*****************************************************************************/ @@ -1385,23 +1406,6 @@ static void ExaRes_ShowExamResult (const struct Exa_Exam *Exam, { extern const char *Hlp_ASSESSMENT_Exams_results; extern const char *Txt_The_user_does_not_exist; - extern const char *Txt_ROLES_SINGUL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; - extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME]; - extern const char *Txt_Questions; - extern const char *Txt_QUESTIONS_valid; - extern const char *Txt_QUESTIONS_invalid; - extern const char *Txt_Valid_answers; - extern const char *Txt_ANSWERS_correct; - extern const char *Txt_ANSWERS_wrong; - extern const char *Txt_ANSWERS_blank; - extern const char *Txt_Score; - extern const char *Txt_valid_score; - extern const char *Txt_Grade; - extern const char *Txt_valid_grade; - bool ShowPhoto; - char PhotoURL[PATH_MAX + 1]; - Dat_StartEndTime_t StartEndTime; - char *Id; struct ExaRes_ICanView ICanView; /***** Check if I can view this print result and its score *****/ @@ -1420,195 +1424,33 @@ static void ExaRes_ShowExamResult (const struct Exa_Exam *Exam, Gbl.Hierarchy.Deg.DegCod, Gbl.Hierarchy.Crs.CrsCod); - - /***** Begin table *****/ - HTM_TABLE_BeginWideMarginPadding (10); - - /***** User *****/ + /***** Check user data *****/ /* Get data of the user who answered the exam print */ if (!Usr_ChkUsrCodAndGetAllUsrDataFromUsrCod (UsrDat,Usr_DONT_GET_PREFS)) Lay_ShowErrorAndExit (Txt_The_user_does_not_exist); if (!Usr_CheckIfICanViewTstExaMchResult (UsrDat)) Lay_NoPermissionExit (); - /* User */ - HTM_TR_Begin (NULL); + /***** Begin table *****/ + HTM_TABLE_BeginWideMarginPadding (10); - HTM_TD_Begin ("class=\"DAT_N RT\""); - HTM_TxtColon (Txt_ROLES_SINGUL_Abc[UsrDat->Roles.InCurrentCrs.Role][UsrDat->Sex]); - HTM_TD_End (); - - HTM_TD_Begin ("class=\"DAT LB\""); - ID_WriteUsrIDs (UsrDat,NULL); - HTM_TxtF (" %s",UsrDat->Surname1); - if (UsrDat->Surname2[0]) - HTM_TxtF (" %s",UsrDat->Surname2); - if (UsrDat->FirstName[0]) - HTM_TxtF (", %s",UsrDat->FirstName); - HTM_BR (); - ShowPhoto = Pho_ShowingUsrPhotoIsAllowed (UsrDat,PhotoURL); - Pho_ShowUsrPhoto (UsrDat,ShowPhoto ? PhotoURL : - NULL, - "PHOTO45x60",Pho_ZOOM,false); - HTM_TD_End (); - - HTM_TR_End (); + /***** User *****/ + ExaRes_ShowExamResultUser (UsrDat); /***** Start/end time (for user in this exam print) *****/ - for (StartEndTime = (Dat_StartEndTime_t) 0; - StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1); - StartEndTime++) - { - HTM_TR_Begin (NULL); - - HTM_TD_Begin ("class=\"DAT_N RT\""); - HTM_TxtColon (Txt_START_END_TIME[StartEndTime]); - HTM_TD_End (); - - if (asprintf (&Id,"match_%u",(unsigned) StartEndTime) < 0) - Lay_NotEnoughMemoryExit (); - HTM_TD_Begin ("id=\"%s\" class=\"DAT LB\"",Id); - Dat_WriteLocalDateHMSFromUTC (Id,Print->TimeUTC[StartEndTime], - Gbl.Prefs.DateFormat,Dat_SEPARATOR_COMMA, - true,true,true,0x7); - HTM_TD_End (); - free (Id); - - HTM_TR_End (); - } + ExaRes_ShowExamResultTime (Print); /***** Number of questions *****/ - HTM_TR_Begin (NULL); - - HTM_TD_Begin ("class=\"DAT_N RT\""); - HTM_TxtColon (Txt_Questions); - HTM_TD_End (); - - HTM_TD_Begin ("class=\"DAT LB\""); - if (ICanView.Result) - { - HTM_TxtF ("%u",Print->NumQsts.All); - if (Print->NumQsts.All != Print->NumQsts.Valid.Total) - { - HTM_Txt (" ("); - - /* Valid questions */ - HTM_SPAN_Begin ("class=\"DAT_GREEN\""); - HTM_TxtColonNBSP (Txt_QUESTIONS_valid); - HTM_Unsigned (Print->NumQsts.Valid.Total); - HTM_SPAN_End (); - - HTM_TxtF ("; "); - - /* Invalid questions */ - HTM_SPAN_Begin ("class=\"DAT_RED\""); - HTM_TxtColonNBSP (Txt_QUESTIONS_invalid); - HTM_Unsigned (Print->NumQsts.All - Print->NumQsts.Valid.Total); - HTM_SPAN_End (); - - HTM_Txt (")"); - } - } - else - Ico_PutIconNotVisible (); - HTM_TD_End (); - - HTM_TR_End (); + ExaRes_ShowExamResultNumQsts (Print,&ICanView); /***** Number of answers *****/ - HTM_TR_Begin (NULL); - - HTM_TD_Begin ("class=\"DAT_N RT\""); - HTM_TxtColon (Txt_Valid_answers); - HTM_TD_End (); - - HTM_TD_Begin ("class=\"DAT LB\""); - if (ICanView.Result) - HTM_TxtF ("%s(pi=1): %u; " - "%s(-1≤pi<0): %u; " - "%s(pi=0): %u; " - "%s(0<pi<1): %u; " - "%s(pi=0): %u", - Txt_ANSWERS_correct,Print->NumQsts.Valid.Correct, - Txt_ANSWERS_wrong ,Print->NumQsts.Valid.Wrong.Negative, - Txt_ANSWERS_wrong ,Print->NumQsts.Valid.Wrong.Zero, - Txt_ANSWERS_wrong ,Print->NumQsts.Valid.Wrong.Positive, - Txt_ANSWERS_blank ,Print->NumQsts.Valid.Blank); - else - Ico_PutIconNotVisible (); - HTM_TD_End (); - - HTM_TR_End (); + ExaRes_ShowExamResultNumAnss (Print,&ICanView); /***** Score *****/ - HTM_TR_Begin (NULL); - - HTM_TD_Begin ("class=\"DAT_N RT\""); - HTM_TxtColon (Txt_Score); - HTM_TD_End (); - - HTM_TD_Begin ("class=\"DAT LB\""); - if (ICanView.Score) - { - /* Score counting all questions */ - if (Print->NumQsts.All == Print->NumQsts.Valid.Total) - HTM_STRONG_Begin (); - HTM_Double2Decimals (Print->Score.All); - HTM_Txt ("/"); - HTM_Unsigned (Print->NumQsts.All); - if (Print->NumQsts.All == Print->NumQsts.Valid.Total) - HTM_STRONG_End (); - - /* Scoure counting only valid questions */ - if (Print->NumQsts.All != Print->NumQsts.Valid.Total) - { - HTM_Txt ("; "); - HTM_TxtColonNBSP (Txt_valid_score); - HTM_STRONG_Begin (); - HTM_Double2Decimals (Print->Score.Valid); - HTM_Txt ("/"); - HTM_Unsigned (Print->NumQsts.Valid.Total); - HTM_STRONG_End (); - } - } - else - Ico_PutIconNotVisible (); - HTM_TD_End (); - - HTM_TR_End (); + ExaRes_ShowExamResultScore (Print,&ICanView); /***** Grade *****/ - HTM_TR_Begin (NULL); - - HTM_TD_Begin ("class=\"DAT_N RT\""); - HTM_TxtColon (Txt_Grade); - HTM_TD_End (); - - HTM_TD_Begin ("class=\"DAT LB\""); - if (ICanView.Score) - { - /* Grade counting all questions */ - if (Print->NumQsts.All == Print->NumQsts.Valid.Total) - HTM_STRONG_Begin (); - TstPrn_ComputeAndShowGrade (Print->NumQsts.All,Print->Score.All,Exam->MaxGrade); - if (Print->NumQsts.All == Print->NumQsts.Valid.Total) - HTM_STRONG_End (); - - /* Grade counting only valid questions */ - if (Print->NumQsts.All != Print->NumQsts.Valid.Total) - { - HTM_Txt ("; "); - HTM_TxtColonNBSP (Txt_valid_grade); - HTM_STRONG_Begin (); - TstPrn_ComputeAndShowGrade (Print->NumQsts.Valid.Total,Print->Score.Valid,Exam->MaxGrade); - HTM_STRONG_End (); - } - } - else - Ico_PutIconNotVisible (); - HTM_TD_End (); - - HTM_TR_End (); + ExaRes_ShowExamResultGrade (Exam,Print,&ICanView); /***** Write answers and solutions *****/ if (ICanView.Result) @@ -1746,6 +1588,273 @@ static void ExaRes_ComputeValidPrintScore (struct ExaPrn_Print *Print) } } +/*****************************************************************************/ +/************************ Show user row in exam result ***********************/ +/*****************************************************************************/ + +void ExaRes_ShowExamResultUser (struct UsrData *UsrDat) + { + extern const char *Txt_ROLES_SINGUL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS]; + bool ShowPhoto; + char PhotoURL[PATH_MAX + 1]; + + /***** Row begin *****/ + HTM_TR_Begin (NULL); + + /***** Label *****/ + HTM_TD_Begin ("class=\"DAT_N RT\""); + HTM_TxtColon (Txt_ROLES_SINGUL_Abc[UsrDat->Roles.InCurrentCrs.Role][UsrDat->Sex]); + HTM_TD_End (); + + /***** User's data *****/ + HTM_TD_Begin ("class=\"DAT LB\""); + ID_WriteUsrIDs (UsrDat,NULL); + HTM_TxtF (" %s",UsrDat->Surname1); + if (UsrDat->Surname2[0]) + HTM_TxtF (" %s",UsrDat->Surname2); + if (UsrDat->FirstName[0]) + HTM_TxtF (", %s",UsrDat->FirstName); + HTM_BR (); + ShowPhoto = Pho_ShowingUsrPhotoIsAllowed (UsrDat,PhotoURL); + Pho_ShowUsrPhoto (UsrDat,ShowPhoto ? PhotoURL : + NULL, + "PHOTO45x60",Pho_ZOOM,false); + HTM_TD_End (); + + /***** Row end *****/ + HTM_TR_End (); + } + +/*****************************************************************************/ +/********************* Show start/end time in exam print *********************/ +/*****************************************************************************/ + +static void ExaRes_ShowExamResultTime (struct ExaPrn_Print *Print) + { + extern const char *Txt_START_END_TIME[Dat_NUM_START_END_TIME]; + Dat_StartEndTime_t StartEndTime; + char *Id; + + for (StartEndTime = (Dat_StartEndTime_t) 0; + StartEndTime <= (Dat_StartEndTime_t) (Dat_NUM_START_END_TIME - 1); + StartEndTime++) + { + /***** Row begin *****/ + HTM_TR_Begin (NULL); + + /***** Label *****/ + HTM_TD_Begin ("class=\"DAT_N RT\""); + HTM_TxtColon (Txt_START_END_TIME[StartEndTime]); + HTM_TD_End (); + + /***** Time *****/ + if (asprintf (&Id,"match_%u",(unsigned) StartEndTime) < 0) + Lay_NotEnoughMemoryExit (); + HTM_TD_Begin ("id=\"%s\" class=\"DAT LB\"",Id); + Dat_WriteLocalDateHMSFromUTC (Id,Print->TimeUTC[StartEndTime], + Gbl.Prefs.DateFormat,Dat_SEPARATOR_COMMA, + true,true,true,0x7); + HTM_TD_End (); + free (Id); + + /***** Row end *****/ + HTM_TR_End (); + } + } + +/*****************************************************************************/ +/******************* Show number of questions in exam print ******************/ +/*****************************************************************************/ + +static void ExaRes_ShowExamResultNumQsts (struct ExaPrn_Print *Print, + const struct ExaRes_ICanView *ICanView) + { + extern const char *Txt_Questions; + extern const char *Txt_QUESTIONS_valid; + extern const char *Txt_QUESTIONS_invalid; + + /***** Row begin *****/ + HTM_TR_Begin (NULL); + + /***** Label *****/ + HTM_TD_Begin ("class=\"DAT_N RT\""); + HTM_TxtColon (Txt_Questions); + HTM_TD_End (); + + /***** Number of questions *****/ + HTM_TD_Begin ("class=\"DAT LB\""); + if (ICanView->Result) + { + HTM_TxtF ("%u",Print->NumQsts.All); + if (Print->NumQsts.All != Print->NumQsts.Valid.Total) + { + HTM_Txt (" ("); + + /* Valid questions */ + HTM_SPAN_Begin ("class=\"DAT_GREEN\""); + HTM_TxtColonNBSP (Txt_QUESTIONS_valid); + HTM_Unsigned (Print->NumQsts.Valid.Total); + HTM_SPAN_End (); + + HTM_TxtF ("; "); + + /* Invalid questions */ + HTM_SPAN_Begin ("class=\"DAT_RED\""); + HTM_TxtColonNBSP (Txt_QUESTIONS_invalid); + HTM_Unsigned (Print->NumQsts.All - Print->NumQsts.Valid.Total); + HTM_SPAN_End (); + + HTM_Txt (")"); + } + } + else + Ico_PutIconNotVisible (); + HTM_TD_End (); + + /***** Row end *****/ + HTM_TR_End (); + } + +/*****************************************************************************/ +/******************** Show number of answers in exam print *******************/ +/*****************************************************************************/ + +static void ExaRes_ShowExamResultNumAnss (struct ExaPrn_Print *Print, + const struct ExaRes_ICanView *ICanView) + { + extern const char *Txt_Valid_answers; + extern const char *Txt_ANSWERS_correct; + extern const char *Txt_ANSWERS_wrong; + extern const char *Txt_ANSWERS_blank; + + /***** Row begin *****/ + HTM_TR_Begin (NULL); + + /***** Label *****/ + HTM_TD_Begin ("class=\"DAT_N RT\""); + HTM_TxtColon (Txt_Valid_answers); + HTM_TD_End (); + + /***** Number of answers *****/ + HTM_TD_Begin ("class=\"DAT LB\""); + if (ICanView->Result) + HTM_TxtF ("%s(pi=1): %u; " + "%s(-1≤pi<0): %u; " + "%s(pi=0): %u; " + "%s(0<pi<1): %u; " + "%s(pi=0): %u", + Txt_ANSWERS_correct,Print->NumQsts.Valid.Correct, + Txt_ANSWERS_wrong ,Print->NumQsts.Valid.Wrong.Negative, + Txt_ANSWERS_wrong ,Print->NumQsts.Valid.Wrong.Zero, + Txt_ANSWERS_wrong ,Print->NumQsts.Valid.Wrong.Positive, + Txt_ANSWERS_blank ,Print->NumQsts.Valid.Blank); + else + Ico_PutIconNotVisible (); + HTM_TD_End (); + + /***** Row end *****/ + HTM_TR_End (); + } + +/*****************************************************************************/ +/************************** Show score in exam print *************************/ +/*****************************************************************************/ + +static void ExaRes_ShowExamResultScore (struct ExaPrn_Print *Print, + const struct ExaRes_ICanView *ICanView) + { + extern const char *Txt_Score; + extern const char *Txt_valid_score; + + /***** Row begin *****/ + HTM_TR_Begin (NULL); + + /***** Label *****/ + HTM_TD_Begin ("class=\"DAT_N RT\""); + HTM_TxtColon (Txt_Score); + HTM_TD_End (); + + /***** Score *****/ + HTM_TD_Begin ("class=\"DAT LB\""); + if (ICanView->Score) + { + /* Score counting all questions */ + if (Print->NumQsts.All == Print->NumQsts.Valid.Total) + HTM_STRONG_Begin (); + HTM_Double2Decimals (Print->Score.All); + HTM_Txt ("/"); + HTM_Unsigned (Print->NumQsts.All); + if (Print->NumQsts.All == Print->NumQsts.Valid.Total) + HTM_STRONG_End (); + + /* Scoure counting only valid questions */ + if (Print->NumQsts.All != Print->NumQsts.Valid.Total) + { + HTM_Txt ("; "); + HTM_TxtColonNBSP (Txt_valid_score); + HTM_STRONG_Begin (); + HTM_Double2Decimals (Print->Score.Valid); + HTM_Txt ("/"); + HTM_Unsigned (Print->NumQsts.Valid.Total); + HTM_STRONG_End (); + } + } + else + Ico_PutIconNotVisible (); + HTM_TD_End (); + + /***** Row end *****/ + HTM_TR_End (); + } + +/*****************************************************************************/ +/************************** Show grade in exam print *************************/ +/*****************************************************************************/ + +static void ExaRes_ShowExamResultGrade (const struct Exa_Exam *Exam, + struct ExaPrn_Print *Print, + const struct ExaRes_ICanView *ICanView) + { + extern const char *Txt_Grade; + extern const char *Txt_valid_grade; + + /***** Row begin *****/ + HTM_TR_Begin (NULL); + + /***** Label *****/ + HTM_TD_Begin ("class=\"DAT_N RT\""); + HTM_TxtColon (Txt_Grade); + HTM_TD_End (); + + /***** Grade *****/ + HTM_TD_Begin ("class=\"DAT LB\""); + if (ICanView->Score) + { + /* Grade counting all questions */ + if (Print->NumQsts.All == Print->NumQsts.Valid.Total) + HTM_STRONG_Begin (); + TstPrn_ComputeAndShowGrade (Print->NumQsts.All,Print->Score.All,Exam->MaxGrade); + if (Print->NumQsts.All == Print->NumQsts.Valid.Total) + HTM_STRONG_End (); + + /* Grade counting only valid questions */ + if (Print->NumQsts.All != Print->NumQsts.Valid.Total) + { + HTM_Txt ("; "); + HTM_TxtColonNBSP (Txt_valid_grade); + HTM_STRONG_Begin (); + TstPrn_ComputeAndShowGrade (Print->NumQsts.Valid.Total,Print->Score.Valid,Exam->MaxGrade); + HTM_STRONG_End (); + } + } + else + Ico_PutIconNotVisible (); + HTM_TD_End (); + + /***** Row end *****/ + HTM_TR_End (); + } + /*****************************************************************************/ /************** Show user's and correct answers of a test exam ***************/ /*****************************************************************************/ diff --git a/swad_exam_result.h b/swad_exam_result.h index 73835b6d..98f509a5 100644 --- a/swad_exam_result.h +++ b/swad_exam_result.h @@ -50,5 +50,6 @@ void ExaRes_ShowAllResultsInExa (void); void ExaRes_ShowAllResultsInSes (void); void ExaRes_ShowOneExaResult (void); +void ExaRes_ShowExamResultUser (struct UsrData *UsrDat); #endif diff --git a/swad_help_URL.c b/swad_help_URL.c index 61993b1d..15855380 100644 --- a/swad_help_URL.c +++ b/swad_help_URL.c @@ -1621,6 +1621,27 @@ const char *Hlp_ASSESSMENT_Exams_questions = "ASSESSMENT.Exams.en#questions"; #endif +const char *Hlp_ASSESSMENT_Exams_answer_exam = +#if L==1 + "ASSESSMENT.Exams.es#responder-examen"; +#elif L==2 + "ASSESSMENT.Exams.en#answer-exam"; +#elif L==3 + "ASSESSMENT.Exams.en#answer-exam"; +#elif L==4 + "ASSESSMENT.Exams.es#responder-examen"; +#elif L==5 + "ASSESSMENT.Exams.en#answer-exam"; +#elif L==6 + "ASSESSMENT.Exams.es#responder-examen"; +#elif L==7 + "ASSESSMENT.Exams.en#answer-exam"; +#elif L==8 + "ASSESSMENT.Exams.en#answer-exam"; +#elif L==9 + "ASSESSMENT.Exams.en#answer-exam"; +#endif + const char *Hlp_ASSESSMENT_Exams_results = #if L==1 "ASSESSMENT.Exams.es#resultados"; diff --git a/swad_photo.c b/swad_photo.c index e0bc98cf..a0415e28 100644 --- a/swad_photo.c +++ b/swad_photo.c @@ -1598,8 +1598,8 @@ static void Pho_ComputeAveragePhoto (long DegCod,Usr_Sex_t Sex,Rol_Role_t Role, extern const char *Usr_StringsSexDB[Usr_NUM_SEXS]; unsigned NumUsr; char PathPrivRelPhoto[PATH_MAX + 1]; // Relative path to private photo, to calculate average face - char PathRelAvgPhoto[PATH_MAX + 1]; - char FileNamePhotoNames[PATH_MAX + 1]; + char *PathRelAvgPhoto; + char *FileNamePhotoNames; FILE *FilePhotoNames = NULL; // Initialized to avoid warning char StrCallToProgram[3 * (PATH_MAX + 1)]; // Call to photo processing program int ReturnCode; @@ -1615,18 +1615,18 @@ static void Pho_ComputeAveragePhoto (long DegCod,Usr_Sex_t Sex,Rol_Role_t Role, *NumStds = *NumStdsWithPhoto = 0; /***** Build name for file with average photo *****/ - snprintf (PathRelAvgPhoto,sizeof (PathRelAvgPhoto), - "%s/%ld_%s.jpg", - DirAvgPhotosRelPath,DegCod,Usr_StringsSexDB[Sex]); + if (asprintf (&PathRelAvgPhoto,"%s/%ld_%s.jpg", + DirAvgPhotosRelPath,DegCod,Usr_StringsSexDB[Sex]) < 0) + Lay_NotEnoughMemoryExit (); /***** Remove old file if exists *****/ if (Fil_CheckIfPathExists (PathRelAvgPhoto)) // If file exists unlink (PathRelAvgPhoto); /***** Build names for text file with photo paths *****/ - snprintf (FileNamePhotoNames,sizeof (FileNamePhotoNames), - "%s/%ld.txt", - Cfg_PATH_PHOTO_TMP_PRIVATE,DegCod); + if (asprintf (&FileNamePhotoNames,"%s/%ld.txt", + Cfg_PATH_PHOTO_TMP_PRIVATE,DegCod) < 0) + Lay_NotEnoughMemoryExit (); if ((FilePhotoNames = fopen (FileNamePhotoNames,"wb")) == NULL) Lay_ShowErrorAndExit ("Can not open file to compute average photo."); @@ -1667,6 +1667,9 @@ static void Pho_ComputeAveragePhoto (long DegCod,Usr_Sex_t Sex,Rol_Role_t Role, Lay_ShowErrorAndExit ("The average photo has not been computed successfully."); } + free (PathRelAvgPhoto); + free (FileNamePhotoNames); + /***** Time used to compute the stats of this degree *****/ if (gettimeofday (&tvEndComputingStat, &tz)) // Error in gettimeofday diff --git a/swad_string.c b/swad_string.c index a798e410..252a96e4 100644 --- a/swad_string.c +++ b/swad_string.c @@ -1456,7 +1456,8 @@ void Str_ChangeFormat (Str_ChangeFrom_t ChangeFrom,Str_ChangeTo_t ChangeTo, Lay_ShowErrorAndExit ("Space allocated to string is full."); /* Copy to appropiate place the special character string */ - strncpy (PtrDst,StrSpecialChar,LengthSpecStrDst); + // strncpy (PtrDst,StrSpecialChar,LengthSpecStrDst); + strcpy (PtrDst,StrSpecialChar); /* Increment pointer to character after ';' */ PtrSrc += LengthSpecStrSrc; diff --git a/swad_zip.c b/swad_zip.c index 63dc33a9..444a4b0a 100644 --- a/swad_zip.c +++ b/swad_zip.c @@ -25,9 +25,11 @@ /*********************************** Headers *********************************/ /*****************************************************************************/ +#define _GNU_SOURCE // For asprintf #include // For scandir, etc. #include // For errno #include // For PATH_MAX +#include // For asprintf #include // For system... #include // For string functions... #include // For mkdir... @@ -357,7 +359,7 @@ static void ZIP_CompressFolderIntoZIP (void) NAME_MAX + 1 + NAME_MAX + 1]; int Result; - char FileNameZIP[NAME_MAX + 1]; + char *FileNameZIP; char PathFileZIP[PATH_MAX + 1]; struct stat FileStatus; char URLWithSpaces[PATH_MAX + 1]; @@ -395,10 +397,10 @@ static void ZIP_CompressFolderIntoZIP (void) Lay_ShowErrorAndExit ("Can not change to temporary folder for compression."); /***** Create public zip file with the assignment and works *****/ - snprintf (FileNameZIP,sizeof (FileNameZIP), - "%s.zip", - strcmp (Gbl.FileBrowser.FilFolLnk.Name,".") ? Gbl.FileBrowser.FilFolLnk.Name : - Txt_ROOT_FOLDER_EXTERNAL_NAMES[Gbl.FileBrowser.Type]); + if (asprintf (&FileNameZIP,"%s.zip", + strcmp (Gbl.FileBrowser.FilFolLnk.Name,".") ? Gbl.FileBrowser.FilFolLnk.Name : + Txt_ROOT_FOLDER_EXTERNAL_NAMES[Gbl.FileBrowser.Type]) < 0) + Lay_NotEnoughMemoryExit (); snprintf (PathFileZIP,sizeof (PathFileZIP), "%s/%s/%s/%s", Cfg_PATH_FILE_BROWSER_TMP_PUBLIC, @@ -414,29 +416,30 @@ static void ZIP_CompressFolderIntoZIP (void) if (chdir (Cfg_PATH_CGI_BIN)) Lay_ShowErrorAndExit ("Can not change to cgi-bin folder."); - /***** If the zip command has been sucessful, write the link to zip file *****/ - if (Result == 0) - { - /***** Get file size *****/ - if (lstat (PathFileZIP,&FileStatus)) // On success ==> 0 is returned - Lay_ShowErrorAndExit ("Can not get information about a file or folder."); - else - { - /***** Create URL pointing to ZIP file *****/ - snprintf (URLWithSpaces,sizeof (URLWithSpaces), - "%s/%s/%s/%s", - Cfg_URL_FILE_BROWSER_TMP_PUBLIC, - Gbl.FileBrowser.TmpPubDir.L, - Gbl.FileBrowser.TmpPubDir.R, - FileNameZIP); - Str_CopyStrChangingSpaces (URLWithSpaces,URL,PATH_MAX); // In HTML, URL must have no spaces - - /****** Link to download file *****/ - ZIP_ShowLinkToDownloadZIP (FileNameZIP,URL,FileStatus.st_size,UncompressedSize); - } - } - else + /***** If the zip command has not been sucessful, abort *****/ + if (Result) Lay_ShowErrorAndExit ("Can not compress files into zip file."); + + /***** If the zip command has been sucessful, write the link to zip file *****/ + /* Get file size */ + if (lstat (PathFileZIP,&FileStatus)) // On success ==> 0 is returned + Lay_ShowErrorAndExit ("Can not get information about a file or folder."); + else + { + /* Create URL pointing to ZIP file */ + snprintf (URLWithSpaces,sizeof (URLWithSpaces), + "%s/%s/%s/%s", + Cfg_URL_FILE_BROWSER_TMP_PUBLIC, + Gbl.FileBrowser.TmpPubDir.L, + Gbl.FileBrowser.TmpPubDir.R, + FileNameZIP); + Str_CopyStrChangingSpaces (URLWithSpaces,URL,PATH_MAX); // In HTML, URL must have no spaces + + /** Link to download file */ + ZIP_ShowLinkToDownloadZIP (FileNameZIP,URL,FileStatus.st_size,UncompressedSize); + } + + free (FileNameZIP); } /***** Remove the directory of compression *****/