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 *****/